@snappedly-tools/shipyard 0.5.0 → 0.7.0-staging.36081473933
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 +64 -117
- package/dist/MountConfig-BHnKnA4h.d.ts +145 -0
- package/dist/{chunk-WAXEMZUV.js → chunk-44I2BL6E.js} +225 -33
- package/dist/chunk-44I2BL6E.js.map +1 -0
- package/dist/{chunk-56TDSWFU.js → chunk-JI3HDDMS.js} +3 -3
- package/dist/{chunk-56TDSWFU.js.map → chunk-JI3HDDMS.js.map} +1 -1
- package/dist/{chunk-FDYOTN55.js → chunk-L6PX5QTU.js} +253 -878
- package/dist/chunk-L6PX5QTU.js.map +1 -0
- package/dist/index.d.ts +117 -97
- package/dist/index.js +349 -353
- package/dist/index.js.map +1 -1
- package/dist/main.js +285 -153
- package/dist/main.js.map +1 -1
- package/dist/sandboxes/docker.d.ts +1 -3
- package/dist/sandboxes/docker.js +2 -4
- package/dist/templates/parallel-planner/block-scope.sh +160 -0
- package/dist/templates/parallel-planner/conflict-prompt.md +22 -0
- package/dist/templates/parallel-planner/handoff.sh +175 -0
- package/dist/templates/parallel-planner/implement-prompt.md +10 -56
- package/dist/templates/parallel-planner/main.mts +493 -189
- package/dist/templates/parallel-planner/merge-prompt.md +9 -21
- package/dist/templates/parallel-planner/plan-prompt.md +5 -31
- package/dist/templates/parallel-planner/planner-branch.mts +151 -0
- package/dist/templates/parallel-planner/select-issues.mjs +788 -0
- package/dist/templates/parallel-planner/setup.sh +51 -0
- package/dist/templates/parallel-planner/spec-wave-prompt.md +16 -0
- package/dist/templates/parallel-planner/template.json +1 -1
- package/dist/templates/parallel-planner/triage-prompt.md +5 -0
- package/dist/templates/parallel-planner/verify-triage.sh +19 -0
- package/dist/templates/parallel-planner-with-review/block-scope.sh +160 -0
- package/dist/templates/parallel-planner-with-review/conflict-prompt.md +22 -0
- package/dist/templates/parallel-planner-with-review/handoff.sh +175 -0
- package/dist/templates/parallel-planner-with-review/implement-prompt.md +10 -56
- package/dist/templates/parallel-planner-with-review/main.mts +533 -207
- package/dist/templates/parallel-planner-with-review/merge-prompt.md +9 -21
- package/dist/templates/parallel-planner-with-review/plan-prompt.md +5 -31
- package/dist/templates/parallel-planner-with-review/planner-branch.mts +151 -0
- package/dist/templates/parallel-planner-with-review/review-prompt.md +11 -49
- package/dist/templates/parallel-planner-with-review/select-issues.mjs +788 -0
- package/dist/templates/parallel-planner-with-review/setup.sh +51 -0
- package/dist/templates/parallel-planner-with-review/spec-wave-prompt.md +16 -0
- package/dist/templates/parallel-planner-with-review/template.json +1 -1
- package/dist/templates/parallel-planner-with-review/triage-prompt.md +5 -0
- package/dist/templates/parallel-planner-with-review/verify-triage.sh +19 -0
- package/dist/templates/sequential-reviewer/block-scope.sh +160 -0
- package/dist/templates/sequential-reviewer/handoff.sh +175 -0
- package/dist/templates/sequential-reviewer/implement-prompt.md +12 -46
- package/dist/templates/sequential-reviewer/main.mts +248 -103
- package/dist/templates/sequential-reviewer/review-prompt.md +11 -49
- package/dist/templates/sequential-reviewer/select-issues.mjs +788 -0
- package/dist/templates/sequential-reviewer/setup.sh +51 -0
- package/dist/templates/sequential-reviewer/template.json +1 -1
- package/dist/templates/sequential-reviewer/triage-prompt.md +5 -0
- package/dist/templates/sequential-reviewer/verify-triage.sh +19 -0
- package/dist/templates/shared/block-scope.sh +160 -0
- package/dist/templates/shared/handoff.sh +175 -0
- package/dist/templates/shared/select-issues.mjs +788 -0
- package/dist/templates/shared/setup.sh +51 -0
- package/dist/templates/shared/triage-prompt.md +5 -0
- package/dist/templates/shared/verify-triage.sh +19 -0
- package/dist/templates/simple-loop/block-scope.sh +160 -0
- package/dist/templates/simple-loop/handoff.sh +175 -0
- package/dist/templates/simple-loop/main.mts +239 -45
- package/dist/templates/simple-loop/prompt.md +12 -46
- package/dist/templates/simple-loop/select-issues.mjs +788 -0
- package/dist/templates/simple-loop/setup.sh +51 -0
- package/dist/templates/simple-loop/template.json +1 -1
- package/dist/templates/simple-loop/triage-prompt.md +5 -0
- package/dist/templates/simple-loop/verify-triage.sh +19 -0
- package/package.json +1 -17
- package/dist/MountConfig-bZoCs4Dd.d.ts +0 -26
- package/dist/SandboxProvider-XJQqEdSf.d.ts +0 -261
- package/dist/chunk-ACD46ZM4.js +0 -136
- package/dist/chunk-ACD46ZM4.js.map +0 -1
- package/dist/chunk-FDYOTN55.js.map +0 -1
- package/dist/chunk-KMGNFXKN.js +0 -38
- package/dist/chunk-KMGNFXKN.js.map +0 -1
- package/dist/chunk-SOJTAJTF.js +0 -78
- package/dist/chunk-SOJTAJTF.js.map +0 -1
- package/dist/chunk-WAXEMZUV.js.map +0 -1
- package/dist/sandboxes/no-sandbox.d.ts +0 -37
- package/dist/sandboxes/no-sandbox.js +0 -4
- package/dist/sandboxes/no-sandbox.js.map +0 -1
- package/dist/sandboxes/vercel.d.ts +0 -104
- package/dist/sandboxes/vercel.js +0 -166
- package/dist/sandboxes/vercel.js.map +0 -1
- package/dist/templates/blank/main.mts +0 -13
- package/dist/templates/blank/prompt.md +0 -12
- package/dist/templates/blank/template.json +0 -4
package/dist/index.js
CHANGED
|
@@ -1,36 +1,25 @@
|
|
|
1
|
-
import { CODEX_MODELS, resolveEnv, formatErrorMessage, buildLogDirectoryName } from './chunk-
|
|
2
|
-
export { CODEX_MODELS, CODEX_REASONING_EFFORTS } from './chunk-
|
|
3
|
-
import { CwdError, resolveCwd, getCurrentBranch, generateTempBranchName, assertNoSymlinkComponents, FileDisplay, ClackDisplay, WorktreeDockerSandboxFactory, SandboxConfig, Display, CLI_NAME, PRODUCT_NAME, pruneStale, create,
|
|
4
|
-
|
|
5
|
-
export { createBindMountSandboxProvider, createIsolatedSandboxProvider } from './chunk-KMGNFXKN.js';
|
|
6
|
-
import { noSandbox } from './chunk-SOJTAJTF.js';
|
|
7
|
-
import './chunk-ACD46ZM4.js';
|
|
1
|
+
import { CODEX_MODELS, resolveEnv, formatErrorMessage, buildLogDirectoryName } from './chunk-JI3HDDMS.js';
|
|
2
|
+
export { CODEX_MODELS, CODEX_REASONING_EFFORTS } from './chunk-JI3HDDMS.js';
|
|
3
|
+
import { CwdError, resolveCwd, getCurrentBranch, generateTempBranchName, assertNoSymlinkComponents, FileDisplay, ClackDisplay, WorktreeDockerSandboxFactory, SandboxConfig, Display, CLI_NAME, PRODUCT_NAME, pruneStale, create, runHostHooks, startSandbox, remove, makeSandboxFromHandle, withSandboxLifecycle, hasUncommittedChanges, shellQuote, registerShutdown, toSessionTransferHandle, SandboxFactory, syncOut, PromptError, CONFIG_DIR, LOGS_DIR, AgentError, SessionCaptureError, PromptExpansionTimeoutError, assertExcludesRepositoryRunner, resolveSafeRelativePath, CopyToWorktreeError, withTimeout, CopyToWorktreeTimeoutError, SilentDisplay, AgentIdleTimeoutError } from './chunk-L6PX5QTU.js';
|
|
4
|
+
export { createIsolatedSandboxProvider } from './chunk-L6PX5QTU.js';
|
|
8
5
|
import { NodeContext, NodeFileSystem } from '@effect/platform-node';
|
|
9
|
-
import { mkdirSync, chmodSync, appendFileSync, constants } from 'fs';
|
|
6
|
+
import { existsSync, mkdirSync, chmodSync, appendFileSync, constants } from 'fs';
|
|
10
7
|
import path, { join, posix, dirname, relative } from 'path';
|
|
11
8
|
import { styleText } from 'util';
|
|
12
9
|
import { Context, Effect, Layer, Clock, Duration, Option, Deferred, Ref, Fiber } from 'effect';
|
|
13
10
|
import { FileSystem } from '@effect/platform';
|
|
14
11
|
import * as clack from '@clack/prompts';
|
|
12
|
+
import { execFile } from 'child_process';
|
|
15
13
|
import { readdir, access, readFile, mkdir, mkdtemp, writeFile, rm, lstat, open, chmod } from 'fs/promises';
|
|
16
14
|
import { homedir, tmpdir } from 'os';
|
|
17
15
|
import { createHmac, timingSafeEqual, createHash, randomUUID } from 'crypto';
|
|
18
16
|
|
|
19
17
|
// src/resumePrecheck.ts
|
|
20
18
|
var assertResumeSessionExists = async (params) => {
|
|
21
|
-
const { provider,
|
|
19
|
+
const { provider, hostRepoDir, resumeSession } = params;
|
|
22
20
|
if (!provider.sessionStorage) {
|
|
23
21
|
throw new Error(`${provider.name} does not support resumeSession`);
|
|
24
22
|
}
|
|
25
|
-
if (sandboxTag === "none") {
|
|
26
|
-
const found = await provider.sessionStorage.findByIdOnHost(resumeSession);
|
|
27
|
-
if (!found.path) {
|
|
28
|
-
throw new Error(
|
|
29
|
-
`resumeSession "${resumeSession}" not found under ${found.searchedRoot}`
|
|
30
|
-
);
|
|
31
|
-
}
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
23
|
const exists = await provider.sessionStorage.existsOnHost(
|
|
35
24
|
hostRepoDir,
|
|
36
25
|
resumeSession
|
|
@@ -424,7 +413,12 @@ var orchestrate = (options) => {
|
|
|
424
413
|
yield* checkAbort();
|
|
425
414
|
yield* display.status(label(`Iteration ${i}/${iterations}`), "info");
|
|
426
415
|
const sandboxResult = yield* factory.withSandbox(
|
|
427
|
-
({
|
|
416
|
+
({
|
|
417
|
+
hostWorktreePath,
|
|
418
|
+
sandboxRepoPath,
|
|
419
|
+
applyToHost,
|
|
420
|
+
sessionTransferHandle
|
|
421
|
+
}, sandbox) => withSandboxLifecycle(
|
|
428
422
|
{
|
|
429
423
|
hostRepoDir,
|
|
430
424
|
sandboxRepoDir: sandboxRepoPath,
|
|
@@ -440,14 +434,14 @@ var orchestrate = (options) => {
|
|
|
440
434
|
(ctx) => Effect.gen(function* () {
|
|
441
435
|
const iterationResumeSession = i === 1 ? options.resumeSession : void 0;
|
|
442
436
|
const iterationForkSession = i === 1 ? options.forkSession : void 0;
|
|
443
|
-
if (iterationResumeSession &&
|
|
437
|
+
if (iterationResumeSession && sessionTransferHandle && provider.sessionStorage) {
|
|
444
438
|
yield* display.status(label("Resuming session"), "info");
|
|
445
439
|
yield* Effect.tryPromise({
|
|
446
440
|
try: () => provider.sessionStorage.resumeIntoSandbox({
|
|
447
441
|
hostCwd: hostRepoDir,
|
|
448
442
|
sandboxCwd: ctx.sandboxRepoDir,
|
|
449
443
|
sessionId: iterationResumeSession,
|
|
450
|
-
handle:
|
|
444
|
+
handle: sessionTransferHandle
|
|
451
445
|
}),
|
|
452
446
|
catch: (e) => new SessionCaptureError({
|
|
453
447
|
message: `Session resume failed: ${e instanceof Error ? e.message : String(e)}`,
|
|
@@ -539,14 +533,14 @@ var orchestrate = (options) => {
|
|
|
539
533
|
yield* display.status(label("Agent stopped"), "info");
|
|
540
534
|
let sessionFilePath;
|
|
541
535
|
let usage = streamUsage;
|
|
542
|
-
if (provider.captureSessions && provider.sessionStorage && sessionId &&
|
|
536
|
+
if (provider.captureSessions && provider.sessionStorage && sessionId && sessionTransferHandle) {
|
|
543
537
|
yield* display.status(label("Capturing session"), "info");
|
|
544
538
|
yield* Effect.tryPromise({
|
|
545
539
|
try: () => provider.sessionStorage.captureToHost({
|
|
546
540
|
hostCwd: hostRepoDir,
|
|
547
541
|
sandboxCwd: ctx.sandboxRepoDir,
|
|
548
542
|
sessionId,
|
|
549
|
-
handle:
|
|
543
|
+
handle: sessionTransferHandle
|
|
550
544
|
}),
|
|
551
545
|
catch: (e) => new SessionCaptureError({
|
|
552
546
|
message: `Session capture failed: ${e instanceof Error ? e.message : String(e)}`,
|
|
@@ -1019,18 +1013,9 @@ async function run(options) {
|
|
|
1019
1013
|
agent: provider
|
|
1020
1014
|
} = options;
|
|
1021
1015
|
validateMaxIterations(maxIterations);
|
|
1022
|
-
const branchStrategy = options.branchStrategy ??
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
throw new Error(
|
|
1026
|
-
"head branch strategy is not supported with isolated providers"
|
|
1027
|
-
);
|
|
1028
|
-
}
|
|
1029
|
-
if (effectiveBranchType === "head" && options.copyToWorktree && options.copyToWorktree.length > 0) {
|
|
1030
|
-
throw new Error(
|
|
1031
|
-
"copyToWorktree is not supported with head branch strategy. In head mode the host working directory is bind-mounted directly."
|
|
1032
|
-
);
|
|
1033
|
-
}
|
|
1016
|
+
const branchStrategy = options.branchStrategy ?? {
|
|
1017
|
+
type: "merge-to-head"
|
|
1018
|
+
};
|
|
1034
1019
|
if (options.resumeSession && maxIterations > 1) {
|
|
1035
1020
|
throw new Error(
|
|
1036
1021
|
"resumeSession cannot be combined with maxIterations > 1. Resume applies to iteration 1 only; multi-iteration resume semantics are not supported."
|
|
@@ -1064,7 +1049,6 @@ async function run(options) {
|
|
|
1064
1049
|
if (options.resumeSession) {
|
|
1065
1050
|
await assertResumeSessionExists({
|
|
1066
1051
|
provider,
|
|
1067
|
-
sandboxTag: options.sandbox.tag,
|
|
1068
1052
|
hostRepoDir,
|
|
1069
1053
|
resumeSession: options.resumeSession
|
|
1070
1054
|
});
|
|
@@ -1096,8 +1080,8 @@ async function run(options) {
|
|
|
1096
1080
|
const currentHostBranch = await Effect.runPromise(
|
|
1097
1081
|
getCurrentBranch(hostRepoDir)
|
|
1098
1082
|
);
|
|
1099
|
-
const resolvedBranch =
|
|
1100
|
-
const targetBranch =
|
|
1083
|
+
const resolvedBranch = branch ?? generateTempBranchName(options.name);
|
|
1084
|
+
const targetBranch = branchStrategy.type === "merge-to-head" ? currentHostBranch : void 0;
|
|
1101
1085
|
const resolvedLogging = options.logging ?? {
|
|
1102
1086
|
type: "file",
|
|
1103
1087
|
path: buildDefaultLogPath(
|
|
@@ -1182,7 +1166,7 @@ async function run(options) {
|
|
|
1182
1166
|
builtInArgKeysSet
|
|
1183
1167
|
);
|
|
1184
1168
|
}
|
|
1185
|
-
const orchestrateBranch =
|
|
1169
|
+
const orchestrateBranch = branch;
|
|
1186
1170
|
const orchestrateResult = yield* orchestrate({
|
|
1187
1171
|
hostRepoDir,
|
|
1188
1172
|
iterations: maxIterations,
|
|
@@ -1333,25 +1317,16 @@ var raceAbortSignal = (effect, signal) => {
|
|
|
1333
1317
|
var interactive = async (options) => {
|
|
1334
1318
|
options.signal?.throwIfAborted();
|
|
1335
1319
|
const { prompt, promptFile, hooks, agent: provider } = options;
|
|
1336
|
-
const resolvedSandbox = options.sandbox
|
|
1337
|
-
const branchStrategy = options.branchStrategy ??
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
"head branch strategy is not supported with isolated providers"
|
|
1341
|
-
);
|
|
1342
|
-
}
|
|
1343
|
-
if (branchStrategy.type === "head" && options.copyToWorktree && options.copyToWorktree.length > 0) {
|
|
1344
|
-
throw new Error(
|
|
1345
|
-
"copyToWorktree is not supported with head branch strategy. In head mode the host working directory is bind-mounted directly."
|
|
1346
|
-
);
|
|
1347
|
-
}
|
|
1320
|
+
const resolvedSandbox = options.sandbox;
|
|
1321
|
+
const branchStrategy = options.branchStrategy ?? {
|
|
1322
|
+
type: "merge-to-head"
|
|
1323
|
+
};
|
|
1348
1324
|
if (!provider.buildInteractiveArgs) {
|
|
1349
1325
|
throw new Error(
|
|
1350
1326
|
`Agent provider "${provider.name}" does not support buildInteractiveArgs, required for interactive sessions.`
|
|
1351
1327
|
);
|
|
1352
1328
|
}
|
|
1353
1329
|
const branch = branchStrategy.type === "branch" ? branchStrategy.branch : void 0;
|
|
1354
|
-
const isHeadMode = branchStrategy.type === "head";
|
|
1355
1330
|
const sandboxProvider = resolvedSandbox;
|
|
1356
1331
|
const inner = Effect.gen(function* () {
|
|
1357
1332
|
const hostRepoDir = yield* resolveCwd(options.cwd);
|
|
@@ -1368,7 +1343,7 @@ var interactive = async (options) => {
|
|
|
1368
1343
|
});
|
|
1369
1344
|
const effectiveEnv = { ...env, ...options.env ?? {} };
|
|
1370
1345
|
const currentHostBranch = yield* getCurrentBranch(hostRepoDir);
|
|
1371
|
-
const resolvedBranch =
|
|
1346
|
+
const resolvedBranch = branch ?? generateTempBranchName(options.name);
|
|
1372
1347
|
let substitutedPrompt = rawPrompt;
|
|
1373
1348
|
if (hasPromptSource && !isInlinePrompt) {
|
|
1374
1349
|
const userArgs = options.promptArgs ?? {};
|
|
@@ -1408,86 +1383,38 @@ var interactive = async (options) => {
|
|
|
1408
1383
|
const userArgs = options.promptArgs ?? {};
|
|
1409
1384
|
yield* validateNoArgsWithInlinePrompt(userArgs);
|
|
1410
1385
|
}
|
|
1411
|
-
const lifecycleBranch =
|
|
1386
|
+
const lifecycleBranch = branch;
|
|
1412
1387
|
yield* d.intro(options.name ?? `${CLI_NAME} interactive`);
|
|
1413
1388
|
yield* d.summary("Interactive Session", {
|
|
1414
1389
|
Agent: options.name ?? provider.name,
|
|
1415
1390
|
Sandbox: sandboxProvider.name,
|
|
1416
1391
|
Branch: resolvedBranch
|
|
1417
1392
|
});
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
Effect.andThen(
|
|
1425
|
-
branch ? create(hostRepoDir, { branch }) : create(hostRepoDir, { name: options.name })
|
|
1426
|
-
)
|
|
1393
|
+
const worktreeInfo = yield* d.taskLog(
|
|
1394
|
+
"Creating worktree",
|
|
1395
|
+
() => pruneStale(hostRepoDir).pipe(
|
|
1396
|
+
Effect.catchAll(() => Effect.void),
|
|
1397
|
+
Effect.andThen(
|
|
1398
|
+
branch ? create(hostRepoDir, { branch }) : create(hostRepoDir, { name: options.name })
|
|
1427
1399
|
)
|
|
1428
|
-
)
|
|
1429
|
-
|
|
1400
|
+
)
|
|
1401
|
+
);
|
|
1430
1402
|
const handle = yield* Effect.gen(function* () {
|
|
1431
|
-
if (
|
|
1432
|
-
|
|
1433
|
-
yield* d.taskLog(
|
|
1434
|
-
"Copying files to worktree",
|
|
1435
|
-
() => copyToWorktree(
|
|
1436
|
-
options.copyToWorktree,
|
|
1437
|
-
hostRepoDir,
|
|
1438
|
-
worktreeInfo.path,
|
|
1439
|
-
options.timeouts?.copyToWorktreeMs
|
|
1440
|
-
)
|
|
1441
|
-
);
|
|
1442
|
-
}
|
|
1443
|
-
if (hooks?.host?.onWorktreeReady?.length) {
|
|
1444
|
-
yield* runHostHooks(hooks.host.onWorktreeReady, worktreeInfo.path);
|
|
1445
|
-
}
|
|
1446
|
-
} else if (hooks?.host?.onWorktreeReady?.length) {
|
|
1447
|
-
yield* runHostHooks(hooks.host.onWorktreeReady, hostRepoDir);
|
|
1448
|
-
}
|
|
1449
|
-
if (sandboxProvider.tag === "none") {
|
|
1450
|
-
const worktreePath = isHeadMode ? hostRepoDir : worktreeInfo.path;
|
|
1451
|
-
return yield* Effect.promise(
|
|
1452
|
-
() => sandboxProvider.create({
|
|
1453
|
-
worktreePath,
|
|
1454
|
-
env: effectiveEnv
|
|
1455
|
-
})
|
|
1456
|
-
);
|
|
1457
|
-
} else if (sandboxProvider.tag === "isolated") {
|
|
1458
|
-
const startResult = yield* d.taskLog(
|
|
1459
|
-
"Starting sandbox",
|
|
1460
|
-
() => startSandbox({
|
|
1461
|
-
provider: sandboxProvider,
|
|
1462
|
-
hostRepoDir: worktreeInfo.path,
|
|
1463
|
-
sourceRepoDir: hostRepoDir,
|
|
1464
|
-
env: effectiveEnv,
|
|
1465
|
-
copyPaths: options.copyToWorktree
|
|
1466
|
-
})
|
|
1467
|
-
);
|
|
1468
|
-
return startResult.handle;
|
|
1469
|
-
} else {
|
|
1470
|
-
const gitPath = join(hostRepoDir, ".git");
|
|
1471
|
-
const rawGitMounts = yield* resolveGitMounts(gitPath);
|
|
1472
|
-
const worktreeOrRepoPath = isHeadMode ? hostRepoDir : worktreeInfo.path;
|
|
1473
|
-
const gitMounts = yield* patchGitMountsForWindows(
|
|
1474
|
-
rawGitMounts,
|
|
1475
|
-
worktreeOrRepoPath,
|
|
1476
|
-
SANDBOX_REPO_DIR
|
|
1477
|
-
);
|
|
1478
|
-
const startResult = yield* d.taskLog(
|
|
1479
|
-
"Starting sandbox",
|
|
1480
|
-
() => startSandbox({
|
|
1481
|
-
provider: sandboxProvider,
|
|
1482
|
-
hostRepoDir,
|
|
1483
|
-
env: effectiveEnv,
|
|
1484
|
-
worktreeOrRepoPath,
|
|
1485
|
-
gitMounts,
|
|
1486
|
-
repoDir: SANDBOX_REPO_DIR
|
|
1487
|
-
})
|
|
1488
|
-
);
|
|
1489
|
-
return startResult.handle;
|
|
1403
|
+
if (hooks?.host?.onWorktreeReady?.length) {
|
|
1404
|
+
yield* runHostHooks(hooks.host.onWorktreeReady, worktreeInfo.path);
|
|
1490
1405
|
}
|
|
1406
|
+
const startResult = yield* d.taskLog(
|
|
1407
|
+
"Starting sandbox",
|
|
1408
|
+
() => startSandbox({
|
|
1409
|
+
provider: sandboxProvider,
|
|
1410
|
+
hostRepoDir: worktreeInfo.path,
|
|
1411
|
+
sourceRepoDir: hostRepoDir,
|
|
1412
|
+
env: effectiveEnv,
|
|
1413
|
+
copyPaths: options.copyToWorktree,
|
|
1414
|
+
copyTimeoutMs: options.timeouts?.copyToWorktreeMs
|
|
1415
|
+
})
|
|
1416
|
+
);
|
|
1417
|
+
return startResult.handle;
|
|
1491
1418
|
}).pipe(
|
|
1492
1419
|
Effect.tapError(
|
|
1493
1420
|
() => worktreeInfo ? remove(worktreeInfo.path).pipe(
|
|
@@ -1504,14 +1431,14 @@ var interactive = async (options) => {
|
|
|
1504
1431
|
const interactiveExecFn = handle.interactiveExec.bind(handle);
|
|
1505
1432
|
const sandbox = makeSandboxFromHandle(handle);
|
|
1506
1433
|
const worktreePath = handle.worktreePath;
|
|
1507
|
-
const applyToHost =
|
|
1434
|
+
const applyToHost = () => syncOut(worktreeInfo.path, handle);
|
|
1508
1435
|
const lifecycleEffect = withSandboxLifecycle(
|
|
1509
1436
|
{
|
|
1510
1437
|
hostRepoDir,
|
|
1511
1438
|
sandboxRepoDir: worktreePath,
|
|
1512
1439
|
hooks,
|
|
1513
1440
|
branch: lifecycleBranch,
|
|
1514
|
-
hostWorktreePath:
|
|
1441
|
+
hostWorktreePath: worktreeInfo.path,
|
|
1515
1442
|
applyToHost,
|
|
1516
1443
|
timeouts: options.timeouts
|
|
1517
1444
|
},
|
|
@@ -1524,7 +1451,7 @@ var interactive = async (options) => {
|
|
|
1524
1451
|
);
|
|
1525
1452
|
const interactiveArgs = provider.buildInteractiveArgs({
|
|
1526
1453
|
prompt: fullPrompt,
|
|
1527
|
-
dangerouslySkipPermissions:
|
|
1454
|
+
dangerouslySkipPermissions: true
|
|
1528
1455
|
});
|
|
1529
1456
|
const result4 = yield* raceAbortSignal(
|
|
1530
1457
|
Effect.promise(
|
|
@@ -1596,6 +1523,15 @@ var interactive = async (options) => {
|
|
|
1596
1523
|
}
|
|
1597
1524
|
return result3;
|
|
1598
1525
|
};
|
|
1526
|
+
var runRequiredSandboxHook = (sandbox, command, cwd, sudo) => Effect.flatMap(
|
|
1527
|
+
sandbox.exec(command, { cwd, sudo }),
|
|
1528
|
+
(result3) => result3.exitCode === 0 ? Effect.succeed(result3) : Effect.fail(
|
|
1529
|
+
new Error(
|
|
1530
|
+
`Sandbox setup failed (exit ${result3.exitCode}): ${command}
|
|
1531
|
+
${result3.stderr}`
|
|
1532
|
+
)
|
|
1533
|
+
)
|
|
1534
|
+
);
|
|
1599
1535
|
var buildSandboxHandle = (ctx, close) => {
|
|
1600
1536
|
const {
|
|
1601
1537
|
branch,
|
|
@@ -1604,7 +1540,7 @@ var buildSandboxHandle = (ctx, close) => {
|
|
|
1604
1540
|
sandboxRepoDir,
|
|
1605
1541
|
sandbox,
|
|
1606
1542
|
providerHandle,
|
|
1607
|
-
|
|
1543
|
+
sessionTransferHandle,
|
|
1608
1544
|
applyToHost,
|
|
1609
1545
|
timeouts,
|
|
1610
1546
|
branchStrategy
|
|
@@ -1635,7 +1571,6 @@ var buildSandboxHandle = (ctx, close) => {
|
|
|
1635
1571
|
if (runOptions.resumeSession) {
|
|
1636
1572
|
await assertResumeSessionExists({
|
|
1637
1573
|
provider,
|
|
1638
|
-
sandboxTag: ctx.providerTag,
|
|
1639
1574
|
hostRepoDir,
|
|
1640
1575
|
resumeSession: runOptions.resumeSession
|
|
1641
1576
|
});
|
|
@@ -1706,7 +1641,7 @@ var buildSandboxHandle = (ctx, close) => {
|
|
|
1706
1641
|
hostWorktreePath: worktreePath,
|
|
1707
1642
|
sandboxRepoPath: sandboxRepoDir,
|
|
1708
1643
|
applyToHost,
|
|
1709
|
-
|
|
1644
|
+
sessionTransferHandle
|
|
1710
1645
|
},
|
|
1711
1646
|
sandbox
|
|
1712
1647
|
).pipe(
|
|
@@ -1926,24 +1861,13 @@ var buildSandboxHandle = (ctx, close) => {
|
|
|
1926
1861
|
var createSandboxFromWorktree = async (options) => {
|
|
1927
1862
|
const { branch, worktreePath, hostRepoDir } = options;
|
|
1928
1863
|
const isTestMode = !!options._test?.buildSandbox;
|
|
1929
|
-
if (options.copyToWorktree && options.copyToWorktree.length > 0 && options.sandbox.tag !== "isolated") {
|
|
1930
|
-
await Effect.runPromise(
|
|
1931
|
-
copyToWorktree(
|
|
1932
|
-
options.copyToWorktree,
|
|
1933
|
-
hostRepoDir,
|
|
1934
|
-
worktreePath,
|
|
1935
|
-
options.timeouts?.copyToWorktreeMs
|
|
1936
|
-
)
|
|
1937
|
-
);
|
|
1938
|
-
}
|
|
1939
1864
|
let providerHandle;
|
|
1940
1865
|
let sandbox;
|
|
1941
1866
|
let sandboxRepoDir;
|
|
1942
|
-
const isIsolated = options.sandbox.tag === "isolated";
|
|
1943
1867
|
if (isTestMode) {
|
|
1944
1868
|
sandbox = options._test.buildSandbox(worktreePath);
|
|
1945
1869
|
sandboxRepoDir = worktreePath;
|
|
1946
|
-
providerHandle = options._test.
|
|
1870
|
+
providerHandle = options._test.sessionTransferHandle;
|
|
1947
1871
|
} else {
|
|
1948
1872
|
const resolvedEnv = await Effect.runPromise(
|
|
1949
1873
|
resolveEnv(hostRepoDir).pipe(Effect.provide(NodeContext.layer))
|
|
@@ -1954,42 +1878,15 @@ var createSandboxFromWorktree = async (options) => {
|
|
|
1954
1878
|
sandboxProviderEnv: options.sandbox.env
|
|
1955
1879
|
});
|
|
1956
1880
|
const provider = options.sandbox;
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
} else if (provider.tag === "none") {
|
|
1967
|
-
startEffect = startSandbox({
|
|
1968
|
-
provider,
|
|
1969
|
-
hostRepoDir,
|
|
1970
|
-
env,
|
|
1971
|
-
worktreeOrRepoPath: worktreePath
|
|
1972
|
-
});
|
|
1973
|
-
} else {
|
|
1974
|
-
startEffect = resolveGitMounts(join(hostRepoDir, ".git")).pipe(
|
|
1975
|
-
Effect.provide(NodeFileSystem.layer),
|
|
1976
|
-
Effect.catchAll(() => Effect.succeed([])),
|
|
1977
|
-
// Patch git mounts for Windows worktree compatibility (ADR-0006)
|
|
1978
|
-
Effect.flatMap(
|
|
1979
|
-
(gitMounts) => patchGitMountsForWindows(gitMounts, worktreePath, SANDBOX_REPO_DIR)
|
|
1980
|
-
),
|
|
1981
|
-
Effect.flatMap(
|
|
1982
|
-
(gitMounts) => startSandbox({
|
|
1983
|
-
provider,
|
|
1984
|
-
hostRepoDir,
|
|
1985
|
-
env,
|
|
1986
|
-
worktreeOrRepoPath: worktreePath,
|
|
1987
|
-
gitMounts,
|
|
1988
|
-
repoDir: SANDBOX_REPO_DIR
|
|
1989
|
-
})
|
|
1990
|
-
)
|
|
1991
|
-
);
|
|
1992
|
-
}
|
|
1881
|
+
const startEffect = startSandbox({
|
|
1882
|
+
provider,
|
|
1883
|
+
hostRepoDir: worktreePath,
|
|
1884
|
+
sourceRepoDir: hostRepoDir,
|
|
1885
|
+
copySourceDir: worktreePath,
|
|
1886
|
+
env,
|
|
1887
|
+
copyPaths: options.copyToWorktree,
|
|
1888
|
+
copyTimeoutMs: options.timeouts?.copyToWorktreeMs
|
|
1889
|
+
});
|
|
1993
1890
|
const startResult = await Effect.runPromise(startEffect);
|
|
1994
1891
|
providerHandle = startResult.handle;
|
|
1995
1892
|
sandbox = startResult.sandbox;
|
|
@@ -2004,10 +1901,12 @@ var createSandboxFromWorktree = async (options) => {
|
|
|
2004
1901
|
`git config --global --add safe.directory ${shellQuote(sandboxRepoDir)}`
|
|
2005
1902
|
);
|
|
2006
1903
|
const sandboxEffects = (sandboxOnReady ?? []).map(
|
|
2007
|
-
(hook) =>
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
1904
|
+
(hook) => runRequiredSandboxHook(
|
|
1905
|
+
sandbox,
|
|
1906
|
+
hook.command,
|
|
1907
|
+
sandboxRepoDir,
|
|
1908
|
+
hook.sudo
|
|
1909
|
+
)
|
|
2011
1910
|
);
|
|
2012
1911
|
const allEffects = [...sandboxEffects];
|
|
2013
1912
|
if (hostOnReady?.length) {
|
|
@@ -2016,12 +1915,17 @@ var createSandboxFromWorktree = async (options) => {
|
|
|
2016
1915
|
yield* Effect.all(allEffects, {
|
|
2017
1916
|
concurrency: "unbounded"
|
|
2018
1917
|
});
|
|
2019
|
-
})
|
|
1918
|
+
}).pipe(
|
|
1919
|
+
Effect.onError(
|
|
1920
|
+
() => providerHandle ? Effect.promise(() => providerHandle.close().catch(() => {
|
|
1921
|
+
})) : Effect.void
|
|
1922
|
+
)
|
|
1923
|
+
)
|
|
2020
1924
|
);
|
|
2021
1925
|
}
|
|
2022
|
-
const applyToHost =
|
|
1926
|
+
const applyToHost = providerHandle ? () => syncOut(worktreePath, providerHandle) : () => Effect.void;
|
|
2023
1927
|
let closed = false;
|
|
2024
|
-
const
|
|
1928
|
+
const sessionTransferHandle = toSessionTransferHandle(providerHandle);
|
|
2025
1929
|
return buildSandboxHandle(
|
|
2026
1930
|
{
|
|
2027
1931
|
branch,
|
|
@@ -2030,8 +1934,7 @@ var createSandboxFromWorktree = async (options) => {
|
|
|
2030
1934
|
sandboxRepoDir,
|
|
2031
1935
|
sandbox,
|
|
2032
1936
|
providerHandle,
|
|
2033
|
-
|
|
2034
|
-
providerTag: options.sandbox.tag,
|
|
1937
|
+
sessionTransferHandle,
|
|
2035
1938
|
applyToHost,
|
|
2036
1939
|
timeouts: options.timeouts,
|
|
2037
1940
|
branchStrategy: options.branchStrategy
|
|
@@ -2047,7 +1950,6 @@ var createSandboxFromWorktree = async (options) => {
|
|
|
2047
1950
|
var createSandbox = async (options) => {
|
|
2048
1951
|
const { branch } = options;
|
|
2049
1952
|
const isTestMode = !!options._test?.buildSandbox;
|
|
2050
|
-
const isIsolated = options.sandbox.tag === "isolated";
|
|
2051
1953
|
const { hostRepoDir, worktreePath, providerHandle, sandbox, sandboxRepoDir } = await Effect.runPromise(
|
|
2052
1954
|
Effect.gen(function* () {
|
|
2053
1955
|
const hostRepoDir2 = yield* resolveCwd(options.cwd);
|
|
@@ -2059,14 +1961,6 @@ var createSandbox = async (options) => {
|
|
|
2059
1961
|
{ branch, baseBranch: options.baseBranch }
|
|
2060
1962
|
);
|
|
2061
1963
|
const prepared = yield* Effect.gen(function* () {
|
|
2062
|
-
if (options.copyToWorktree && options.copyToWorktree.length > 0 && options.sandbox.tag !== "isolated") {
|
|
2063
|
-
yield* copyToWorktree(
|
|
2064
|
-
options.copyToWorktree,
|
|
2065
|
-
hostRepoDir2,
|
|
2066
|
-
worktreePath2,
|
|
2067
|
-
options.timeouts?.copyToWorktreeMs
|
|
2068
|
-
);
|
|
2069
|
-
}
|
|
2070
1964
|
if (options.hooks?.host?.onWorktreeReady?.length) {
|
|
2071
1965
|
yield* runHostHooks(
|
|
2072
1966
|
options.hooks.host.onWorktreeReady,
|
|
@@ -2079,7 +1973,7 @@ var createSandbox = async (options) => {
|
|
|
2079
1973
|
if (isTestMode) {
|
|
2080
1974
|
sandbox2 = options._test.buildSandbox(worktreePath2);
|
|
2081
1975
|
sandboxRepoDir2 = worktreePath2;
|
|
2082
|
-
providerHandle2 = options._test.
|
|
1976
|
+
providerHandle2 = options._test.sessionTransferHandle;
|
|
2083
1977
|
} else {
|
|
2084
1978
|
const resolvedEnv = yield* resolveEnv(hostRepoDir2);
|
|
2085
1979
|
const env = mergeProviderEnv({
|
|
@@ -2088,39 +1982,14 @@ var createSandbox = async (options) => {
|
|
|
2088
1982
|
sandboxProviderEnv: options.sandbox.env
|
|
2089
1983
|
});
|
|
2090
1984
|
const provider = options.sandbox;
|
|
2091
|
-
const startResult = yield*
|
|
1985
|
+
const startResult = yield* startSandbox({
|
|
2092
1986
|
provider,
|
|
2093
1987
|
hostRepoDir: worktreePath2,
|
|
2094
1988
|
sourceRepoDir: hostRepoDir2,
|
|
2095
1989
|
env,
|
|
2096
|
-
copyPaths: options.copyToWorktree
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
hostRepoDir: hostRepoDir2,
|
|
2100
|
-
env,
|
|
2101
|
-
worktreeOrRepoPath: worktreePath2
|
|
2102
|
-
}) : resolveGitMounts(join(hostRepoDir2, ".git")).pipe(
|
|
2103
|
-
Effect.provide(NodeFileSystem.layer),
|
|
2104
|
-
Effect.catchAll(() => Effect.succeed([])),
|
|
2105
|
-
// Patch git mounts for Windows worktree compatibility (ADR-0006)
|
|
2106
|
-
Effect.flatMap(
|
|
2107
|
-
(gitMounts) => patchGitMountsForWindows(
|
|
2108
|
-
gitMounts,
|
|
2109
|
-
worktreePath2,
|
|
2110
|
-
SANDBOX_REPO_DIR
|
|
2111
|
-
)
|
|
2112
|
-
),
|
|
2113
|
-
Effect.flatMap(
|
|
2114
|
-
(gitMounts) => startSandbox({
|
|
2115
|
-
provider,
|
|
2116
|
-
hostRepoDir: hostRepoDir2,
|
|
2117
|
-
env,
|
|
2118
|
-
worktreeOrRepoPath: worktreePath2,
|
|
2119
|
-
gitMounts,
|
|
2120
|
-
repoDir: SANDBOX_REPO_DIR
|
|
2121
|
-
})
|
|
2122
|
-
)
|
|
2123
|
-
);
|
|
1990
|
+
copyPaths: options.copyToWorktree,
|
|
1991
|
+
copyTimeoutMs: options.timeouts?.copyToWorktreeMs
|
|
1992
|
+
});
|
|
2124
1993
|
providerHandle2 = startResult.handle;
|
|
2125
1994
|
sandbox2 = startResult.sandbox;
|
|
2126
1995
|
sandboxRepoDir2 = startResult.worktreePath;
|
|
@@ -2133,10 +2002,12 @@ var createSandbox = async (options) => {
|
|
|
2133
2002
|
`git config --global --add safe.directory ${shellQuote(sandboxRepoDir2)}`
|
|
2134
2003
|
);
|
|
2135
2004
|
const sandboxEffects = (sandboxOnReady ?? []).map(
|
|
2136
|
-
(hook) =>
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2005
|
+
(hook) => runRequiredSandboxHook(
|
|
2006
|
+
sandbox2,
|
|
2007
|
+
hook.command,
|
|
2008
|
+
sandboxRepoDir2,
|
|
2009
|
+
hook.sudo
|
|
2010
|
+
)
|
|
2140
2011
|
);
|
|
2141
2012
|
const allEffects = [...sandboxEffects];
|
|
2142
2013
|
if (hostOnReady?.length) {
|
|
@@ -2163,7 +2034,7 @@ var createSandbox = async (options) => {
|
|
|
2163
2034
|
return { hostRepoDir: hostRepoDir2, worktreePath: worktreePath2, ...prepared };
|
|
2164
2035
|
}).pipe(Effect.provide(NodeContext.layer))
|
|
2165
2036
|
);
|
|
2166
|
-
const applyToHost =
|
|
2037
|
+
const applyToHost = providerHandle ? () => syncOut(worktreePath, providerHandle) : () => Effect.void;
|
|
2167
2038
|
let closed = false;
|
|
2168
2039
|
const forceCleanup = () => {
|
|
2169
2040
|
console.error(`
|
|
@@ -2193,7 +2064,7 @@ Worktree preserved at ${worktreePath}`);
|
|
|
2193
2064
|
})
|
|
2194
2065
|
);
|
|
2195
2066
|
};
|
|
2196
|
-
const
|
|
2067
|
+
const sessionTransferHandle = toSessionTransferHandle(providerHandle);
|
|
2197
2068
|
return buildSandboxHandle(
|
|
2198
2069
|
{
|
|
2199
2070
|
branch,
|
|
@@ -2202,8 +2073,7 @@ Worktree preserved at ${worktreePath}`);
|
|
|
2202
2073
|
sandboxRepoDir,
|
|
2203
2074
|
sandbox,
|
|
2204
2075
|
providerHandle,
|
|
2205
|
-
|
|
2206
|
-
providerTag: options.sandbox.tag,
|
|
2076
|
+
sessionTransferHandle,
|
|
2207
2077
|
applyToHost,
|
|
2208
2078
|
timeouts: options.timeouts
|
|
2209
2079
|
},
|
|
@@ -2213,6 +2083,82 @@ Worktree preserved at ${worktreePath}`);
|
|
|
2213
2083
|
}
|
|
2214
2084
|
);
|
|
2215
2085
|
};
|
|
2086
|
+
var COPY_TO_WORKTREE_TIMEOUT_MS = 6e4;
|
|
2087
|
+
var getCopyOnWriteFlags = (platform) => platform === "darwin" ? ["-cR"] : ["-R", "--reflink=auto"];
|
|
2088
|
+
var copyToWorktree = (paths, hostRepoDir, worktreePath, timeoutMs) => {
|
|
2089
|
+
const effectiveTimeout = timeoutMs ?? COPY_TO_WORKTREE_TIMEOUT_MS;
|
|
2090
|
+
return Effect.gen(function* () {
|
|
2091
|
+
const cowFlags = getCopyOnWriteFlags(process.platform);
|
|
2092
|
+
for (const relativePath of paths) {
|
|
2093
|
+
let src;
|
|
2094
|
+
let dest;
|
|
2095
|
+
try {
|
|
2096
|
+
assertExcludesRepositoryRunner(relativePath);
|
|
2097
|
+
src = resolveSafeRelativePath(hostRepoDir, relativePath, "copy path");
|
|
2098
|
+
dest = resolveSafeRelativePath(worktreePath, relativePath, "copy path");
|
|
2099
|
+
} catch (error) {
|
|
2100
|
+
return yield* Effect.fail(
|
|
2101
|
+
new CopyToWorktreeError({
|
|
2102
|
+
message: `Refusing unsafe copy path ${relativePath}: ${error instanceof Error ? error.message : String(error)}`,
|
|
2103
|
+
path: relativePath,
|
|
2104
|
+
stderr: error instanceof Error ? error.message : String(error),
|
|
2105
|
+
exitCode: null
|
|
2106
|
+
})
|
|
2107
|
+
);
|
|
2108
|
+
}
|
|
2109
|
+
if (!existsSync(src)) {
|
|
2110
|
+
continue;
|
|
2111
|
+
}
|
|
2112
|
+
yield* Effect.tryPromise({
|
|
2113
|
+
try: async () => {
|
|
2114
|
+
await assertNoSymlinkComponents(hostRepoDir, src, "copy source");
|
|
2115
|
+
await assertNoSymlinkComponents(worktreePath, dest, "copy target");
|
|
2116
|
+
},
|
|
2117
|
+
catch: (error) => new CopyToWorktreeError({
|
|
2118
|
+
message: `Refusing symlinked copy path ${relativePath}: ${error instanceof Error ? error.message : String(error)}`,
|
|
2119
|
+
path: relativePath,
|
|
2120
|
+
stderr: error instanceof Error ? error.message : String(error),
|
|
2121
|
+
exitCode: null
|
|
2122
|
+
})
|
|
2123
|
+
});
|
|
2124
|
+
yield* Effect.async((resume) => {
|
|
2125
|
+
execFile("cp", [...cowFlags, src, dest], (error) => {
|
|
2126
|
+
if (error) {
|
|
2127
|
+
execFile("cp", ["-R", src, dest], (fallbackError, _, stderr) => {
|
|
2128
|
+
if (fallbackError) {
|
|
2129
|
+
resume(
|
|
2130
|
+
Effect.fail(
|
|
2131
|
+
new CopyToWorktreeError({
|
|
2132
|
+
message: `Failed to copy ${relativePath} to worktree: ${stderr || fallbackError.message}`,
|
|
2133
|
+
path: relativePath,
|
|
2134
|
+
stderr: stderr || fallbackError.message,
|
|
2135
|
+
exitCode: typeof fallbackError.code === "number" ? fallbackError.code : null
|
|
2136
|
+
})
|
|
2137
|
+
)
|
|
2138
|
+
);
|
|
2139
|
+
} else {
|
|
2140
|
+
resume(Effect.succeed(void 0));
|
|
2141
|
+
}
|
|
2142
|
+
});
|
|
2143
|
+
} else {
|
|
2144
|
+
resume(Effect.succeed(void 0));
|
|
2145
|
+
}
|
|
2146
|
+
});
|
|
2147
|
+
});
|
|
2148
|
+
}
|
|
2149
|
+
}).pipe(
|
|
2150
|
+
withTimeout(
|
|
2151
|
+
effectiveTimeout,
|
|
2152
|
+
() => new CopyToWorktreeTimeoutError({
|
|
2153
|
+
message: `Copying files to worktree timed out after ${effectiveTimeout}ms`,
|
|
2154
|
+
timeoutMs: effectiveTimeout,
|
|
2155
|
+
paths
|
|
2156
|
+
})
|
|
2157
|
+
)
|
|
2158
|
+
);
|
|
2159
|
+
};
|
|
2160
|
+
|
|
2161
|
+
// src/createWorktree.ts
|
|
2216
2162
|
var createWorktree = async (options) => {
|
|
2217
2163
|
const branch = options.branchStrategy.type === "branch" ? options.branchStrategy.branch : void 0;
|
|
2218
2164
|
const baseBranch = options.branchStrategy.type === "branch" ? options.branchStrategy.baseBranch : void 0;
|
|
@@ -2259,7 +2205,7 @@ var createWorktree = async (options) => {
|
|
|
2259
2205
|
const worktreeInteractive = async (opts) => {
|
|
2260
2206
|
opts.signal?.throwIfAborted();
|
|
2261
2207
|
const { prompt, promptFile, hooks, agent: provider } = opts;
|
|
2262
|
-
const resolvedSandbox = opts.sandbox
|
|
2208
|
+
const resolvedSandbox = opts.sandbox;
|
|
2263
2209
|
if (!provider.buildInteractiveArgs) {
|
|
2264
2210
|
throw new Error(
|
|
2265
2211
|
`Agent provider "${provider.name}" does not support buildInteractiveArgs, required for interactive sessions.`
|
|
@@ -2302,46 +2248,19 @@ var createWorktree = async (options) => {
|
|
|
2302
2248
|
Sandbox: resolvedSandbox.name,
|
|
2303
2249
|
Branch: worktreeInfo.branch
|
|
2304
2250
|
});
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
hostRepoDir: worktreeInfo.path,
|
|
2319
|
-
sourceRepoDir: hostRepoDir,
|
|
2320
|
-
env: effectiveEnv
|
|
2321
|
-
})
|
|
2322
|
-
);
|
|
2323
|
-
handle = startResult.handle;
|
|
2324
|
-
} else {
|
|
2325
|
-
const gitPath = join(hostRepoDir, ".git");
|
|
2326
|
-
const rawGitMounts = yield* resolveGitMounts(gitPath);
|
|
2327
|
-
const gitMounts = yield* patchGitMountsForWindows(
|
|
2328
|
-
rawGitMounts,
|
|
2329
|
-
worktreeInfo.path,
|
|
2330
|
-
SANDBOX_REPO_DIR
|
|
2331
|
-
);
|
|
2332
|
-
const startResult = yield* d.taskLog(
|
|
2333
|
-
"Starting sandbox",
|
|
2334
|
-
() => startSandbox({
|
|
2335
|
-
provider: resolvedSandbox,
|
|
2336
|
-
hostRepoDir,
|
|
2337
|
-
env: effectiveEnv,
|
|
2338
|
-
worktreeOrRepoPath: worktreeInfo.path,
|
|
2339
|
-
gitMounts,
|
|
2340
|
-
repoDir: SANDBOX_REPO_DIR
|
|
2341
|
-
})
|
|
2342
|
-
);
|
|
2343
|
-
handle = startResult.handle;
|
|
2344
|
-
}
|
|
2251
|
+
const startResult = yield* d.taskLog(
|
|
2252
|
+
"Starting sandbox",
|
|
2253
|
+
() => startSandbox({
|
|
2254
|
+
provider: resolvedSandbox,
|
|
2255
|
+
hostRepoDir: worktreeInfo.path,
|
|
2256
|
+
sourceRepoDir: hostRepoDir,
|
|
2257
|
+
copySourceDir: worktreeInfo.path,
|
|
2258
|
+
env: effectiveEnv,
|
|
2259
|
+
copyPaths: options.copyToWorktree,
|
|
2260
|
+
copyTimeoutMs: options.timeouts?.copyToWorktreeMs
|
|
2261
|
+
})
|
|
2262
|
+
);
|
|
2263
|
+
const handle = startResult.handle;
|
|
2345
2264
|
return yield* Effect.gen(function* () {
|
|
2346
2265
|
if (!handle.interactiveExec) {
|
|
2347
2266
|
throw new Error(
|
|
@@ -2351,7 +2270,7 @@ var createWorktree = async (options) => {
|
|
|
2351
2270
|
const interactiveExecFn = handle.interactiveExec.bind(handle);
|
|
2352
2271
|
const sandbox = makeSandboxFromHandle(handle);
|
|
2353
2272
|
const worktreePath = handle.worktreePath;
|
|
2354
|
-
const applyToHost =
|
|
2273
|
+
const applyToHost = () => syncOut(worktreeInfo.path, handle);
|
|
2355
2274
|
const lifecycleEffect = withSandboxLifecycle(
|
|
2356
2275
|
{
|
|
2357
2276
|
hostRepoDir,
|
|
@@ -2375,7 +2294,7 @@ var createWorktree = async (options) => {
|
|
|
2375
2294
|
);
|
|
2376
2295
|
const interactiveArgs = provider.buildInteractiveArgs({
|
|
2377
2296
|
prompt: fullPrompt,
|
|
2378
|
-
dangerouslySkipPermissions:
|
|
2297
|
+
dangerouslySkipPermissions: true
|
|
2379
2298
|
});
|
|
2380
2299
|
const result3 = yield* raceAbortSignal(
|
|
2381
2300
|
Effect.promise(
|
|
@@ -2438,7 +2357,6 @@ var createWorktree = async (options) => {
|
|
|
2438
2357
|
if (opts.resumeSession) {
|
|
2439
2358
|
await assertResumeSessionExists({
|
|
2440
2359
|
provider,
|
|
2441
|
-
sandboxTag: sandboxProvider.tag,
|
|
2442
2360
|
hostRepoDir,
|
|
2443
2361
|
resumeSession: opts.resumeSession
|
|
2444
2362
|
});
|
|
@@ -2473,47 +2391,19 @@ var createWorktree = async (options) => {
|
|
|
2473
2391
|
builtInArgKeysSet
|
|
2474
2392
|
);
|
|
2475
2393
|
}
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
} else if (sandboxProvider.tag === "none") {
|
|
2488
|
-
const startResult = yield* startSandbox({
|
|
2489
|
-
provider: sandboxProvider,
|
|
2490
|
-
hostRepoDir,
|
|
2491
|
-
env: effectiveEnv,
|
|
2492
|
-
worktreeOrRepoPath: worktreeInfo.path
|
|
2493
|
-
});
|
|
2494
|
-
handle = startResult.handle;
|
|
2495
|
-
sandboxRepoDir = startResult.worktreePath;
|
|
2496
|
-
} else {
|
|
2497
|
-
const gitPath = join(hostRepoDir, ".git");
|
|
2498
|
-
const rawGitMounts = yield* resolveGitMounts(gitPath);
|
|
2499
|
-
const gitMounts = yield* patchGitMountsForWindows(
|
|
2500
|
-
rawGitMounts,
|
|
2501
|
-
worktreeInfo.path,
|
|
2502
|
-
SANDBOX_REPO_DIR
|
|
2503
|
-
);
|
|
2504
|
-
const startResult = yield* startSandbox({
|
|
2505
|
-
provider: sandboxProvider,
|
|
2506
|
-
hostRepoDir,
|
|
2507
|
-
env: effectiveEnv,
|
|
2508
|
-
worktreeOrRepoPath: worktreeInfo.path,
|
|
2509
|
-
gitMounts,
|
|
2510
|
-
repoDir: SANDBOX_REPO_DIR
|
|
2511
|
-
});
|
|
2512
|
-
handle = startResult.handle;
|
|
2513
|
-
sandboxRepoDir = startResult.worktreePath;
|
|
2514
|
-
}
|
|
2394
|
+
const startResult = yield* startSandbox({
|
|
2395
|
+
provider: sandboxProvider,
|
|
2396
|
+
hostRepoDir: worktreeInfo.path,
|
|
2397
|
+
sourceRepoDir: hostRepoDir,
|
|
2398
|
+
copySourceDir: worktreeInfo.path,
|
|
2399
|
+
env: effectiveEnv,
|
|
2400
|
+
copyPaths: options.copyToWorktree,
|
|
2401
|
+
copyTimeoutMs: options.timeouts?.copyToWorktreeMs
|
|
2402
|
+
});
|
|
2403
|
+
const handle = startResult.handle;
|
|
2404
|
+
const sandboxRepoDir = startResult.worktreePath;
|
|
2515
2405
|
const sandbox = makeSandboxFromHandle(handle);
|
|
2516
|
-
const applyToHost =
|
|
2406
|
+
const applyToHost = () => syncOut(worktreeInfo.path, handle);
|
|
2517
2407
|
const resolvedLogging = opts.logging ?? {
|
|
2518
2408
|
type: "file",
|
|
2519
2409
|
path: buildDefaultLogPath(
|
|
@@ -2546,14 +2436,14 @@ var createWorktree = async (options) => {
|
|
|
2546
2436
|
NodeFileSystem.layer
|
|
2547
2437
|
);
|
|
2548
2438
|
})() : ClackDisplay.layer;
|
|
2549
|
-
const
|
|
2439
|
+
const sessionTransferHandle = toSessionTransferHandle(handle);
|
|
2550
2440
|
const reuseFactoryLayer = Layer.succeed(SandboxFactory, {
|
|
2551
2441
|
withSandbox: (makeEffect) => makeEffect(
|
|
2552
2442
|
{
|
|
2553
2443
|
hostWorktreePath: worktreeInfo.path,
|
|
2554
2444
|
sandboxRepoPath: sandboxRepoDir,
|
|
2555
2445
|
applyToHost,
|
|
2556
|
-
|
|
2446
|
+
sessionTransferHandle
|
|
2557
2447
|
},
|
|
2558
2448
|
sandbox
|
|
2559
2449
|
).pipe(
|
|
@@ -2634,13 +2524,28 @@ var createWorktree = async (options) => {
|
|
|
2634
2524
|
}
|
|
2635
2525
|
};
|
|
2636
2526
|
const worktreeCreateSandbox = async (opts) => {
|
|
2527
|
+
if (opts.copyToWorktree?.length) {
|
|
2528
|
+
await Effect.runPromise(
|
|
2529
|
+
copyToWorktree(
|
|
2530
|
+
opts.copyToWorktree,
|
|
2531
|
+
hostRepoDir,
|
|
2532
|
+
worktreeInfo.path,
|
|
2533
|
+
opts.timeouts?.copyToWorktreeMs ?? options.timeouts?.copyToWorktreeMs
|
|
2534
|
+
)
|
|
2535
|
+
);
|
|
2536
|
+
}
|
|
2637
2537
|
return createSandboxFromWorktree({
|
|
2638
2538
|
branch: worktreeInfo.branch,
|
|
2639
2539
|
worktreePath: worktreeInfo.path,
|
|
2640
2540
|
hostRepoDir,
|
|
2641
2541
|
sandbox: opts.sandbox,
|
|
2642
2542
|
hooks: opts.hooks,
|
|
2643
|
-
copyToWorktree:
|
|
2543
|
+
copyToWorktree: [
|
|
2544
|
+
.../* @__PURE__ */ new Set([
|
|
2545
|
+
...options.copyToWorktree ?? [],
|
|
2546
|
+
...opts.copyToWorktree ?? []
|
|
2547
|
+
])
|
|
2548
|
+
],
|
|
2644
2549
|
timeouts: opts.timeouts,
|
|
2645
2550
|
branchStrategy: options.branchStrategy,
|
|
2646
2551
|
_test: opts._test
|
|
@@ -3009,8 +2914,7 @@ var makeClaudeSessionStorage = (options) => {
|
|
|
3009
2914
|
sandboxProjectsDir
|
|
3010
2915
|
);
|
|
3011
2916
|
await writeSandboxFile(handle, sandboxPath, rewritten, "claude-res");
|
|
3012
|
-
}
|
|
3013
|
-
findByIdOnHost: (id) => findClaudeSessionOnHost(id, hostProjectsDir)
|
|
2917
|
+
}
|
|
3014
2918
|
};
|
|
3015
2919
|
};
|
|
3016
2920
|
var makeCodexSessionStorage = (options) => {
|
|
@@ -3048,8 +2952,7 @@ var makeCodexSessionStorage = (options) => {
|
|
|
3048
2952
|
const rewritten = transferCodexSession(jsonl, hostCwd, sandboxCwd);
|
|
3049
2953
|
const target = posix.join(sandboxSessionsDir, located.relativePath);
|
|
3050
2954
|
await writeSandboxFile(handle, target, rewritten, "codex-res");
|
|
3051
|
-
}
|
|
3052
|
-
findByIdOnHost: (id) => findCodexSessionOnHost(id, hostSessionsDir)
|
|
2955
|
+
}
|
|
3053
2956
|
};
|
|
3054
2957
|
};
|
|
3055
2958
|
var parseCodexUsage = (usage) => {
|
|
@@ -3096,7 +2999,7 @@ var parseCodexStreamLine = (line) => {
|
|
|
3096
2999
|
};
|
|
3097
3000
|
var codex = (model, options) => {
|
|
3098
3001
|
const modelId = typeof model === "string" ? model : model.model;
|
|
3099
|
-
const effort = options?.effort ?? (typeof model === "string" ? CONFIGURED_CODEX_MODEL_EFFORTS.get(modelId) : model.effort);
|
|
3002
|
+
const effort = options?.effort === null ? void 0 : options?.effort ?? (typeof model === "string" ? CONFIGURED_CODEX_MODEL_EFFORTS.get(modelId) : model.effort);
|
|
3100
3003
|
return {
|
|
3101
3004
|
name: "codex",
|
|
3102
3005
|
env: options?.env ?? {},
|
|
@@ -3357,7 +3260,18 @@ var createWorkBrief = (input) => {
|
|
|
3357
3260
|
"acceptanceCriteria"
|
|
3358
3261
|
),
|
|
3359
3262
|
exclusions: stringArray(input.exclusions, "exclusions"),
|
|
3360
|
-
risk: enumValue(
|
|
3263
|
+
risk: enumValue(
|
|
3264
|
+
input.risk,
|
|
3265
|
+
["low", "medium", "high", "critical", "unknown"],
|
|
3266
|
+
"risk"
|
|
3267
|
+
),
|
|
3268
|
+
...input.scope === void 0 ? {} : {
|
|
3269
|
+
scope: enumValue(
|
|
3270
|
+
input.scope,
|
|
3271
|
+
["small", "substantial", "unknown"],
|
|
3272
|
+
"scope"
|
|
3273
|
+
)
|
|
3274
|
+
},
|
|
3361
3275
|
verification: parseVerification(input.verification),
|
|
3362
3276
|
unresolvedQuestions: stringArray(
|
|
3363
3277
|
input.unresolvedQuestions,
|
|
@@ -3397,7 +3311,18 @@ var parseWorkBrief = (value) => {
|
|
|
3397
3311
|
"acceptanceCriteria"
|
|
3398
3312
|
),
|
|
3399
3313
|
exclusions: stringArray(value.exclusions, "exclusions"),
|
|
3400
|
-
risk: enumValue(
|
|
3314
|
+
risk: enumValue(
|
|
3315
|
+
value.risk,
|
|
3316
|
+
["low", "medium", "high", "critical", "unknown"],
|
|
3317
|
+
"risk"
|
|
3318
|
+
),
|
|
3319
|
+
...value.scope === void 0 ? {} : {
|
|
3320
|
+
scope: enumValue(
|
|
3321
|
+
value.scope,
|
|
3322
|
+
["small", "substantial", "unknown"],
|
|
3323
|
+
"scope"
|
|
3324
|
+
)
|
|
3325
|
+
},
|
|
3401
3326
|
verification: parseVerification(value.verification),
|
|
3402
3327
|
unresolvedQuestions: stringArray(
|
|
3403
3328
|
value.unresolvedQuestions,
|
|
@@ -3453,6 +3378,28 @@ var parseRepositoryPolicy = (value) => {
|
|
|
3453
3378
|
if (!isRecord(value.worker)) {
|
|
3454
3379
|
throw new ContractValidationError("policy.worker must be an object");
|
|
3455
3380
|
}
|
|
3381
|
+
const workerModels = value.worker.models === void 0 ? void 0 : (() => {
|
|
3382
|
+
if (value.worker.model !== void 0) {
|
|
3383
|
+
throw new ContractValidationError(
|
|
3384
|
+
"policy.worker.model cannot be combined with policy.worker.models"
|
|
3385
|
+
);
|
|
3386
|
+
}
|
|
3387
|
+
if (!isRecord(value.worker.models)) {
|
|
3388
|
+
throw new ContractValidationError(
|
|
3389
|
+
"policy.worker.models must be an object"
|
|
3390
|
+
);
|
|
3391
|
+
}
|
|
3392
|
+
return {
|
|
3393
|
+
routine: nonEmptyString(
|
|
3394
|
+
value.worker.models.routine,
|
|
3395
|
+
"policy.worker.models.routine"
|
|
3396
|
+
),
|
|
3397
|
+
strong: nonEmptyString(
|
|
3398
|
+
value.worker.models.strong,
|
|
3399
|
+
"policy.worker.models.strong"
|
|
3400
|
+
)
|
|
3401
|
+
};
|
|
3402
|
+
})();
|
|
3456
3403
|
if (!Array.isArray(value.checks)) {
|
|
3457
3404
|
throw new ContractValidationError("policy.checks must be an array");
|
|
3458
3405
|
}
|
|
@@ -3546,7 +3493,7 @@ var parseRepositoryPolicy = (value) => {
|
|
|
3546
3493
|
authorization: { required, allowedActors, autoStartRisk },
|
|
3547
3494
|
worker: {
|
|
3548
3495
|
provider: nonEmptyString(value.worker.provider, "policy.worker.provider"),
|
|
3549
|
-
model: nonEmptyString(value.worker.model, "policy.worker.model"),
|
|
3496
|
+
...workerModels === void 0 ? { model: nonEmptyString(value.worker.model, "policy.worker.model") } : { models: workerModels },
|
|
3550
3497
|
sandbox: nonEmptyString(value.worker.sandbox, "policy.worker.sandbox"),
|
|
3551
3498
|
skillRevision: nonEmptyString(
|
|
3552
3499
|
value.worker.skillRevision,
|
|
@@ -3562,6 +3509,16 @@ var createRepositoryPolicy = (input) => parseRepositoryPolicy({
|
|
|
3562
3509
|
contractVersion: WORKFLOW_CONTRACT_VERSION,
|
|
3563
3510
|
...input
|
|
3564
3511
|
});
|
|
3512
|
+
var resolveAgentSelection = (policy, phase2, risk, scope) => {
|
|
3513
|
+
const role = phase2 === "review" && !(risk === "low" && scope === "small") ? "strong" : "routine";
|
|
3514
|
+
const worker = policy.worker;
|
|
3515
|
+
const modelPath = worker.models ? `policy.worker.models.${role}` : "policy.worker.model";
|
|
3516
|
+
return Object.freeze({
|
|
3517
|
+
provider: nonEmptyString(worker.provider, "policy.worker.provider"),
|
|
3518
|
+
model: nonEmptyString(worker.models?.[role] ?? worker.model, modelPath),
|
|
3519
|
+
role
|
|
3520
|
+
});
|
|
3521
|
+
};
|
|
3565
3522
|
var parseCheckEvidence = (value) => {
|
|
3566
3523
|
if (!isRecord(value)) {
|
|
3567
3524
|
throw new ContractValidationError("check evidence must be an object");
|
|
@@ -3700,6 +3657,12 @@ var createAssignment = (input) => {
|
|
|
3700
3657
|
briefHash: brief.hash,
|
|
3701
3658
|
policyRevision: input.policy.revision,
|
|
3702
3659
|
skillRevision: brief.skillRevision,
|
|
3660
|
+
agentSelection: resolveAgentSelection(
|
|
3661
|
+
input.policy,
|
|
3662
|
+
input.phase,
|
|
3663
|
+
brief.risk,
|
|
3664
|
+
brief.scope
|
|
3665
|
+
),
|
|
3703
3666
|
base: brief.base,
|
|
3704
3667
|
head: input.head,
|
|
3705
3668
|
createdAt: nonEmptyString(input.createdAt, "assignment.createdAt")
|
|
@@ -4069,6 +4032,25 @@ var parseAssignment = (value) => {
|
|
|
4069
4032
|
throw new Error("Stored assignment base must be an object");
|
|
4070
4033
|
}
|
|
4071
4034
|
const head = candidate.head;
|
|
4035
|
+
const agentSelection = candidate.agentSelection;
|
|
4036
|
+
let parsedAgentSelection;
|
|
4037
|
+
if (agentSelection !== void 0) {
|
|
4038
|
+
if (typeof agentSelection !== "object" || agentSelection === null || Array.isArray(agentSelection)) {
|
|
4039
|
+
throw new Error("Stored assignment agent selection must be an object");
|
|
4040
|
+
}
|
|
4041
|
+
const selection = agentSelection;
|
|
4042
|
+
if (selection.role !== "routine" && selection.role !== "strong") {
|
|
4043
|
+
throw new Error("Stored assignment agent selection role is invalid");
|
|
4044
|
+
}
|
|
4045
|
+
parsedAgentSelection = {
|
|
4046
|
+
provider: requiredString(
|
|
4047
|
+
selection.provider,
|
|
4048
|
+
"assignment.agentSelection.provider"
|
|
4049
|
+
),
|
|
4050
|
+
model: requiredString(selection.model, "assignment.agentSelection.model"),
|
|
4051
|
+
role: selection.role
|
|
4052
|
+
};
|
|
4053
|
+
}
|
|
4072
4054
|
const revision = (value2, path2) => {
|
|
4073
4055
|
if (typeof value2 !== "object" || value2 === null || Array.isArray(value2)) {
|
|
4074
4056
|
throw new Error(`${path2} must be an object`);
|
|
@@ -4112,6 +4094,7 @@ var parseAssignment = (value) => {
|
|
|
4112
4094
|
candidate.skillRevision,
|
|
4113
4095
|
"assignment.skillRevision"
|
|
4114
4096
|
),
|
|
4097
|
+
...parsedAgentSelection === void 0 ? {} : { agentSelection: parsedAgentSelection },
|
|
4115
4098
|
base: revision(base, "assignment.base"),
|
|
4116
4099
|
head: head === void 0 ? void 0 : revision(head, "assignment.head"),
|
|
4117
4100
|
createdAt: requiredString(candidate.createdAt, "assignment.createdAt")
|
|
@@ -4301,9 +4284,6 @@ var PostgresTransaction = class {
|
|
|
4301
4284
|
async one(text2, values, path2) {
|
|
4302
4285
|
return row(await this.client.query(text2, values), path2);
|
|
4303
4286
|
}
|
|
4304
|
-
async optional(text2, values) {
|
|
4305
|
-
return optionalRow(await this.client.query(text2, values));
|
|
4306
|
-
}
|
|
4307
4287
|
async insertEventIfAbsent(event) {
|
|
4308
4288
|
const inserted = await this.client.query(
|
|
4309
4289
|
`INSERT INTO shipyard_events (
|
|
@@ -6031,11 +6011,23 @@ var cancelledResult = (assignment, response, artifacts, message, kind) => ({
|
|
|
6031
6011
|
evidence: response.report.evidence
|
|
6032
6012
|
})
|
|
6033
6013
|
});
|
|
6014
|
+
var sameAgentSelection = (left, right) => left.provider === right.provider && left.model === right.model && left.role === right.role;
|
|
6034
6015
|
var executePhase = async (options) => {
|
|
6035
6016
|
const assignment = deepFreeze(structuredClone(options.assignment));
|
|
6036
6017
|
const trusted = deepFreeze(structuredClone(options.trusted));
|
|
6037
6018
|
const untrusted = deepFreeze(structuredClone(options.untrusted));
|
|
6038
6019
|
const controls = deepFreeze(structuredClone(options.controls));
|
|
6020
|
+
const resolvedSelection = resolveAgentSelection(
|
|
6021
|
+
trusted.policy,
|
|
6022
|
+
assignment.phase,
|
|
6023
|
+
trusted.brief.risk,
|
|
6024
|
+
trusted.brief.scope
|
|
6025
|
+
);
|
|
6026
|
+
const persistedSelection = assignment.agentSelection;
|
|
6027
|
+
if (persistedSelection !== void 0 && !sameAgentSelection(persistedSelection, resolvedSelection)) {
|
|
6028
|
+
throw new Error("Assignment agent selection does not match trusted policy");
|
|
6029
|
+
}
|
|
6030
|
+
const agentSelection = persistedSelection ?? resolvedSelection;
|
|
6039
6031
|
const secretValues = /* @__PURE__ */ new Set();
|
|
6040
6032
|
const controller = new AbortController();
|
|
6041
6033
|
let timedOut = false;
|
|
@@ -6049,6 +6041,7 @@ var executePhase = async (options) => {
|
|
|
6049
6041
|
}, options.controls.timeoutSeconds * 1e3);
|
|
6050
6042
|
const request = {
|
|
6051
6043
|
assignment,
|
|
6044
|
+
agentSelection,
|
|
6052
6045
|
trusted,
|
|
6053
6046
|
untrusted,
|
|
6054
6047
|
controls,
|
|
@@ -6293,6 +6286,23 @@ var executePhase = async (options) => {
|
|
|
6293
6286
|
})
|
|
6294
6287
|
};
|
|
6295
6288
|
};
|
|
6289
|
+
var resolvePhaseAgent = (options, request) => {
|
|
6290
|
+
if (options.resolveAgent === void 0 && request.trusted.policy.worker.models !== void 0) {
|
|
6291
|
+
throw new Error(
|
|
6292
|
+
"An agent resolver is required when repository policy defines worker models"
|
|
6293
|
+
);
|
|
6294
|
+
}
|
|
6295
|
+
const agent = options.resolveAgent === void 0 ? options.agent : options.resolveAgent(request.agentSelection);
|
|
6296
|
+
if (agent === void 0) {
|
|
6297
|
+
throw new Error("The phase engine has no agent for the selected model");
|
|
6298
|
+
}
|
|
6299
|
+
if (agent.name !== request.agentSelection.provider) {
|
|
6300
|
+
throw new Error(
|
|
6301
|
+
`Resolved agent provider "${agent.name}" does not match repository policy provider "${request.agentSelection.provider}"`
|
|
6302
|
+
);
|
|
6303
|
+
}
|
|
6304
|
+
return agent;
|
|
6305
|
+
};
|
|
6296
6306
|
var runResultToResponse = (result3, branch) => {
|
|
6297
6307
|
const commits = result3.commits.map((commit) => commit.sha);
|
|
6298
6308
|
const headSha = commits.at(-1) ?? "";
|
|
@@ -6317,11 +6327,12 @@ var runResultToResponse = (result3, branch) => {
|
|
|
6317
6327
|
};
|
|
6318
6328
|
var createRunPhaseEngineAdapter = (options) => ({
|
|
6319
6329
|
execute: async (request) => {
|
|
6320
|
-
|
|
6330
|
+
const agent = resolvePhaseAgent(options, request);
|
|
6331
|
+
assertToolAllowlistSupport(agent);
|
|
6321
6332
|
const branch = request.checkout.branch;
|
|
6322
6333
|
const baseBranch = request.checkout.immutable ? request.checkout.candidate?.sha ?? request.assignment.base.sha : request.assignment.base.sha;
|
|
6323
6334
|
const result3 = await options.run({
|
|
6324
|
-
agent
|
|
6335
|
+
agent,
|
|
6325
6336
|
sandbox: options.sandbox,
|
|
6326
6337
|
cwd: options.cwd,
|
|
6327
6338
|
prompt: buildPrompt(request),
|
|
@@ -6359,7 +6370,8 @@ var sandboxResultToResponse = (result3, branch) => {
|
|
|
6359
6370
|
};
|
|
6360
6371
|
var createCreateSandboxPhaseEngineAdapter = (options) => ({
|
|
6361
6372
|
execute: async (request) => {
|
|
6362
|
-
|
|
6373
|
+
const agent = resolvePhaseAgent(options, request);
|
|
6374
|
+
assertToolAllowlistSupport(agent);
|
|
6363
6375
|
const branch = request.checkout.branch;
|
|
6364
6376
|
const baseBranch = request.checkout.immutable ? request.checkout.candidate?.sha ?? request.assignment.base.sha : request.assignment.base.sha;
|
|
6365
6377
|
const sandbox = await options.createSandbox({
|
|
@@ -6370,7 +6382,7 @@ var createCreateSandboxPhaseEngineAdapter = (options) => ({
|
|
|
6370
6382
|
});
|
|
6371
6383
|
try {
|
|
6372
6384
|
const result3 = await sandbox.run({
|
|
6373
|
-
agent
|
|
6385
|
+
agent,
|
|
6374
6386
|
prompt: buildPrompt(request),
|
|
6375
6387
|
toolAllowlist: request.controls.toolAllowlist,
|
|
6376
6388
|
maxIterations: request.controls.maxIterations,
|
|
@@ -9012,22 +9024,6 @@ var GitHubIntegration = class {
|
|
|
9012
9024
|
reason: ingest.reason
|
|
9013
9025
|
};
|
|
9014
9026
|
}
|
|
9015
|
-
async recordRejected(input) {
|
|
9016
|
-
const payloadRecord = record(input.payload);
|
|
9017
|
-
const delivery = {
|
|
9018
|
-
deliveryId: input.deliveryId,
|
|
9019
|
-
eventName: input.eventName,
|
|
9020
|
-
repository: payloadRecord ? repositoryName(payloadRecord) ?? "unknown" : "unknown",
|
|
9021
|
-
senderLogin: payloadRecord ? sender(payloadRecord).login : "unknown",
|
|
9022
|
-
receivedAt: this.now(),
|
|
9023
|
-
payloadHash: payloadHash(input.body),
|
|
9024
|
-
payload: input.payload,
|
|
9025
|
-
status: "rejected",
|
|
9026
|
-
reason: input.reason
|
|
9027
|
-
};
|
|
9028
|
-
const stored = await this.options.deliveryStore.recordDeliveryIfAbsent(delivery);
|
|
9029
|
-
if (!stored.inserted) return;
|
|
9030
|
-
}
|
|
9031
9027
|
async rejectStored(delivery, reason) {
|
|
9032
9028
|
await this.options.deliveryStore.updateDelivery({
|
|
9033
9029
|
...delivery,
|
|
@@ -9952,6 +9948,6 @@ var ReleaseIntegration = class {
|
|
|
9952
9948
|
};
|
|
9953
9949
|
var candidateMatchesApproval = (candidate, approval) => sameCandidate(candidate, approval.candidate);
|
|
9954
9950
|
|
|
9955
|
-
export { ContractValidationError, CredentialNotAllowedError, CredentialUnavailableError, CwdError2 as CwdError, GitHubIntegration, GitHubPublication, InMemoryCoordinatorStorage, InMemoryGitHubStore, InMemoryReleaseStore, InMemoryRepairBatchStore, InMemoryTriageStore, LeaseBusyError, LeaseLostError, Output, PostgresCoordinatorStorage, ReleaseIntegration, StructuredOutputError, WORKFLOW_CONTRACT_VERSION, WorkflowCoordinator, WorkflowOperator, candidateMatchesApproval, claudeCode, claudeHostSessionPath, claudeSandboxSessionPath, closeSourceIssue, codex, completeSourceIssue, createAssignment, createCreateSandboxPhaseEngineAdapter, createFakePhaseEngineAdapter, createGitHubIssueBrief, createInMemoryArtifactStore, createRepositoryPolicy, createRunPhaseEngineAdapter, createSandbox, createWorkBrief, createWorktree, defaultInvestigator as defaultTriageInvestigator, encodeProjectPath, evaluateHandoffReadiness, executePhase, findClaudeSessionOnHost, findCodexSessionOnHost, interactive, isAuthorizationAllowed, mergeProtectedCandidate, parseCheckEvidence, parsePhaseResult, parseRepositoryPolicy, parseWorkBrief, prepareHumanHandoff, prepareIndependentReview, processHumanReviewDecision, redact2 as redactOperatorText, releaseCandidateKey, requireTransition, resolveHumanReviewDecision, reviewDecisionFor, run, runAuthorizedImplementation, runBoundedRepair, runIndependentReview, runTriage, scheduleBoundedRepair, transferClaudeSession, transferCodexSession, verifyGitHubWebhookSignature };
|
|
9951
|
+
export { ContractValidationError, CredentialNotAllowedError, CredentialUnavailableError, CwdError2 as CwdError, GitHubIntegration, GitHubPublication, InMemoryCoordinatorStorage, InMemoryGitHubStore, InMemoryReleaseStore, InMemoryRepairBatchStore, InMemoryTriageStore, LeaseBusyError, LeaseLostError, Output, PostgresCoordinatorStorage, ReleaseIntegration, StructuredOutputError, WORKFLOW_CONTRACT_VERSION, WorkflowCoordinator, WorkflowOperator, candidateMatchesApproval, claudeCode, claudeHostSessionPath, claudeSandboxSessionPath, closeSourceIssue, codex, completeSourceIssue, createAssignment, createCreateSandboxPhaseEngineAdapter, createFakePhaseEngineAdapter, createGitHubIssueBrief, createInMemoryArtifactStore, createRepositoryPolicy, createRunPhaseEngineAdapter, createSandbox, createWorkBrief, createWorktree, defaultInvestigator as defaultTriageInvestigator, encodeProjectPath, evaluateHandoffReadiness, executePhase, findClaudeSessionOnHost, findCodexSessionOnHost, interactive, isAuthorizationAllowed, mergeProtectedCandidate, parseCheckEvidence, parsePhaseResult, parseRepositoryPolicy, parseWorkBrief, prepareHumanHandoff, prepareIndependentReview, processHumanReviewDecision, redact2 as redactOperatorText, releaseCandidateKey, requireTransition, resolveAgentSelection, resolveHumanReviewDecision, reviewDecisionFor, run, runAuthorizedImplementation, runBoundedRepair, runIndependentReview, runTriage, scheduleBoundedRepair, transferClaudeSession, transferCodexSession, verifyGitHubWebhookSignature };
|
|
9956
9952
|
//# sourceMappingURL=index.js.map
|
|
9957
9953
|
//# sourceMappingURL=index.js.map
|