@snappedly-tools/shipyard 0.7.0-staging.36081473933 → 0.7.0
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 +41 -34
- package/dist/MountConfig-bZoCs4Dd.d.ts +26 -0
- package/dist/SandboxProvider-XJQqEdSf.d.ts +261 -0
- package/dist/{chunk-JI3HDDMS.js → chunk-56TDSWFU.js} +3 -3
- package/dist/{chunk-JI3HDDMS.js.map → chunk-56TDSWFU.js.map} +1 -1
- package/dist/chunk-ACD46ZM4.js +136 -0
- package/dist/chunk-ACD46ZM4.js.map +1 -0
- package/dist/{chunk-L6PX5QTU.js → chunk-FDYOTN55.js} +887 -262
- package/dist/chunk-FDYOTN55.js.map +1 -0
- package/dist/chunk-KMGNFXKN.js +38 -0
- package/dist/chunk-KMGNFXKN.js.map +1 -0
- package/dist/chunk-SOJTAJTF.js +78 -0
- package/dist/chunk-SOJTAJTF.js.map +1 -0
- package/dist/{chunk-44I2BL6E.js → chunk-WAXEMZUV.js} +33 -225
- package/dist/chunk-WAXEMZUV.js.map +1 -0
- package/dist/index.d.ts +97 -117
- package/dist/index.js +344 -322
- package/dist/index.js.map +1 -1
- package/dist/main.js +139 -235
- package/dist/main.js.map +1 -1
- package/dist/sandboxes/docker.d.ts +3 -1
- package/dist/sandboxes/docker.js +4 -2
- package/dist/sandboxes/no-sandbox.d.ts +37 -0
- package/dist/sandboxes/no-sandbox.js +4 -0
- package/dist/sandboxes/no-sandbox.js.map +1 -0
- package/dist/sandboxes/vercel.d.ts +104 -0
- package/dist/sandboxes/vercel.js +166 -0
- package/dist/sandboxes/vercel.js.map +1 -0
- package/dist/templates/blank/main.mts +13 -0
- package/dist/templates/blank/prompt.md +12 -0
- package/dist/templates/blank/template.json +4 -0
- package/dist/templates/parallel-planner/main.mts +9 -67
- package/dist/templates/parallel-planner-with-review/main.mts +12 -70
- package/dist/templates/sequential-reviewer/main.mts +3 -52
- package/dist/templates/simple-loop/main.mts +2 -51
- package/package.json +17 -1
- package/dist/MountConfig-BHnKnA4h.d.ts +0 -145
- package/dist/chunk-44I2BL6E.js.map +0 -1
- package/dist/chunk-L6PX5QTU.js.map +0 -1
- package/dist/templates/parallel-planner/planner-branch.mts +0 -151
- package/dist/templates/parallel-planner-with-review/planner-branch.mts +0 -151
|
@@ -5,59 +5,9 @@ import { existsSync } from "node:fs";
|
|
|
5
5
|
import * as shipyard from "@snappedly-tools/shipyard";
|
|
6
6
|
import { docker } from "@snappedly-tools/shipyard/sandboxes/docker";
|
|
7
7
|
import { z } from "zod";
|
|
8
|
-
import { resolvePlannerBranch } from "./planner-branch.mjs";
|
|
9
8
|
|
|
10
9
|
if (process.loadEnvFile && existsSync(".shipyard/.env"))
|
|
11
10
|
process.loadEnvFile(".shipyard/.env");
|
|
12
|
-
type ModelRole = "routine" | "strong";
|
|
13
|
-
const CODEX_PROVIDER = true;
|
|
14
|
-
const agentFactory = shipyard.codex;
|
|
15
|
-
type AgentModel = Parameters<typeof agentFactory>[0];
|
|
16
|
-
const readRoleModel = (role: ModelRole): string | undefined => {
|
|
17
|
-
const envName = `SHIPYARD_${role.toUpperCase()}_MODEL`;
|
|
18
|
-
const model = process.env[envName];
|
|
19
|
-
if (model !== undefined && model.trim().length === 0)
|
|
20
|
-
throw new Error(`${envName} must not be empty`);
|
|
21
|
-
return model;
|
|
22
|
-
};
|
|
23
|
-
const roleModels = {
|
|
24
|
-
routine: readRoleModel("routine"),
|
|
25
|
-
strong: readRoleModel("strong"),
|
|
26
|
-
};
|
|
27
|
-
const CODEX_REASONING_EFFORTS = shipyard.CODEX_REASONING_EFFORTS;
|
|
28
|
-
type CodexReasoningEffort = shipyard.CodexReasoningEffort;
|
|
29
|
-
const readCodexReasoningEffort = (
|
|
30
|
-
role: ModelRole,
|
|
31
|
-
): CodexReasoningEffort | undefined => {
|
|
32
|
-
if (!CODEX_PROVIDER) return undefined;
|
|
33
|
-
const envName = `SHIPYARD_CODEX_${role.toUpperCase()}_REASONING_EFFORT`;
|
|
34
|
-
const effort = process.env[envName]?.trim();
|
|
35
|
-
if (!effort) return undefined;
|
|
36
|
-
if (!(CODEX_REASONING_EFFORTS as readonly string[]).includes(effort))
|
|
37
|
-
throw new Error(
|
|
38
|
-
`${envName} must be one of ${CODEX_REASONING_EFFORTS.join(", ")}; received "${effort}"`,
|
|
39
|
-
);
|
|
40
|
-
return effort as CodexReasoningEffort;
|
|
41
|
-
};
|
|
42
|
-
const roleEfforts = {
|
|
43
|
-
routine: readCodexReasoningEffort("routine"),
|
|
44
|
-
strong: readCodexReasoningEffort("strong"),
|
|
45
|
-
};
|
|
46
|
-
const readCodexRoleModel = (role: ModelRole, defaultModel: AgentModel) => {
|
|
47
|
-
if (!CODEX_PROVIDER || typeof defaultModel === "string") return defaultModel;
|
|
48
|
-
const envName = `SHIPYARD_CODEX_${role.toUpperCase()}_MODEL`;
|
|
49
|
-
const model = process.env[envName]?.trim();
|
|
50
|
-
return model ? { ...defaultModel, model } : defaultModel;
|
|
51
|
-
};
|
|
52
|
-
const roleAgent = (role: ModelRole, defaultModel: AgentModel) => {
|
|
53
|
-
const model = roleModels[role] ?? readCodexRoleModel(role, defaultModel);
|
|
54
|
-
const effort = roleEfforts[role];
|
|
55
|
-
if (typeof model !== "string")
|
|
56
|
-
return effort === undefined
|
|
57
|
-
? agentFactory(model)
|
|
58
|
-
: agentFactory(model, { effort });
|
|
59
|
-
return agentFactory(model, { effort: effort ?? null });
|
|
60
|
-
};
|
|
61
11
|
const targetBranch = execFileSync("git", ["branch", "--show-current"], {
|
|
62
12
|
encoding: "utf8",
|
|
63
13
|
}).trim();
|
|
@@ -174,7 +124,7 @@ const runWorker = async (scope: Scope, ticket: Ticket) => {
|
|
|
174
124
|
await sandbox.run({
|
|
175
125
|
name: `triage #${ticket.id}`,
|
|
176
126
|
maxIterations: 1,
|
|
177
|
-
agent:
|
|
127
|
+
agent: shipyard.codex(shipyard.CODEX_MODELS.strong),
|
|
178
128
|
promptFile: "./.shipyard/triage-prompt.md",
|
|
179
129
|
promptArgs: { TASK_ID: ticket.id },
|
|
180
130
|
});
|
|
@@ -182,7 +132,7 @@ const runWorker = async (scope: Scope, ticket: Ticket) => {
|
|
|
182
132
|
const implementation = await sandbox.run({
|
|
183
133
|
name: "implementer",
|
|
184
134
|
maxIterations: 100,
|
|
185
|
-
agent:
|
|
135
|
+
agent: shipyard.codex(shipyard.CODEX_MODELS.routine),
|
|
186
136
|
promptFile: "./.shipyard/implement-prompt.md",
|
|
187
137
|
promptArgs: {
|
|
188
138
|
TASK_ID: ticket.id,
|
|
@@ -195,7 +145,7 @@ const runWorker = async (scope: Scope, ticket: Ticket) => {
|
|
|
195
145
|
const review = await sandbox.run({
|
|
196
146
|
name: "reviewer",
|
|
197
147
|
maxIterations: 1,
|
|
198
|
-
agent:
|
|
148
|
+
agent: shipyard.codex(shipyard.CODEX_MODELS.strong),
|
|
199
149
|
promptFile: "./.shipyard/review-prompt.md",
|
|
200
150
|
promptArgs: {
|
|
201
151
|
TASK_ID: ticket.id,
|
|
@@ -216,21 +166,13 @@ for (let iteration = 0; iteration < 10; iteration++) {
|
|
|
216
166
|
execFileSync("node", [".shipyard/select-issues.mjs"], { encoding: "utf8" }),
|
|
217
167
|
) as Scope[];
|
|
218
168
|
if (!scopes.length) break;
|
|
219
|
-
const localBranches = execFileSync(
|
|
220
|
-
"git",
|
|
221
|
-
["for-each-ref", "--format=%(refname:short)", "refs/heads"],
|
|
222
|
-
{ encoding: "utf8" },
|
|
223
|
-
)
|
|
224
|
-
.split(/\r?\n/)
|
|
225
|
-
.filter(Boolean);
|
|
226
|
-
const plannerBranch = await resolvePlannerBranch(localBranches);
|
|
227
169
|
const plan = await shipyard.run({
|
|
228
170
|
hooks,
|
|
229
171
|
sandbox: docker(),
|
|
230
172
|
name: "planner",
|
|
231
|
-
branchStrategy: { type: "branch", branch:
|
|
173
|
+
branchStrategy: { type: "branch", branch: "shipyard/planner" },
|
|
232
174
|
maxIterations: 1,
|
|
233
|
-
agent:
|
|
175
|
+
agent: shipyard.codex(shipyard.CODEX_MODELS.strong),
|
|
234
176
|
promptFile: "./.shipyard/plan-prompt.md",
|
|
235
177
|
output: shipyard.Output.object({ tag: "plan", schema: planSchema }),
|
|
236
178
|
});
|
|
@@ -358,7 +300,7 @@ for (let iteration = 0; iteration < 10; iteration++) {
|
|
|
358
300
|
const resolution = await wave.run({
|
|
359
301
|
name: "conflict-resolver",
|
|
360
302
|
maxIterations: 10,
|
|
361
|
-
agent:
|
|
303
|
+
agent: shipyard.codex(shipyard.CODEX_MODELS.strong),
|
|
362
304
|
promptFile: "./.shipyard/conflict-prompt.md",
|
|
363
305
|
promptArgs: {
|
|
364
306
|
TASK_ID: ready[index]!.id,
|
|
@@ -412,7 +354,7 @@ for (let iteration = 0; iteration < 10; iteration++) {
|
|
|
412
354
|
const integrated = await wave.run({
|
|
413
355
|
name: "spec-integrator",
|
|
414
356
|
maxIterations: 10,
|
|
415
|
-
agent:
|
|
357
|
+
agent: shipyard.codex(shipyard.CODEX_MODELS.strong),
|
|
416
358
|
promptFile: "./.shipyard/spec-wave-prompt.md",
|
|
417
359
|
promptArgs: {
|
|
418
360
|
TASK_ID: id,
|
|
@@ -452,7 +394,7 @@ for (let iteration = 0; iteration < 10; iteration++) {
|
|
|
452
394
|
await integration.run({
|
|
453
395
|
name: `triage #${id}`,
|
|
454
396
|
maxIterations: 1,
|
|
455
|
-
agent:
|
|
397
|
+
agent: shipyard.codex(shipyard.CODEX_MODELS.strong),
|
|
456
398
|
promptFile: "./.shipyard/triage-prompt.md",
|
|
457
399
|
promptArgs: { TASK_ID: id },
|
|
458
400
|
});
|
|
@@ -460,7 +402,7 @@ for (let iteration = 0; iteration < 10; iteration++) {
|
|
|
460
402
|
const standalone = await integration.run({
|
|
461
403
|
name: "implementer",
|
|
462
404
|
maxIterations: 100,
|
|
463
|
-
agent:
|
|
405
|
+
agent: shipyard.codex(shipyard.CODEX_MODELS.routine),
|
|
464
406
|
promptFile: "./.shipyard/implement-prompt.md",
|
|
465
407
|
promptArgs: {
|
|
466
408
|
TASK_ID: id,
|
|
@@ -474,7 +416,7 @@ for (let iteration = 0; iteration < 10; iteration++) {
|
|
|
474
416
|
const review = await integration.run({
|
|
475
417
|
name: "reviewer",
|
|
476
418
|
maxIterations: 1,
|
|
477
|
-
agent:
|
|
419
|
+
agent: shipyard.codex(shipyard.CODEX_MODELS.strong),
|
|
478
420
|
promptFile: "./.shipyard/review-prompt.md",
|
|
479
421
|
promptArgs: {
|
|
480
422
|
TASK_ID: id,
|
|
@@ -487,7 +429,7 @@ for (let iteration = 0; iteration < 10; iteration++) {
|
|
|
487
429
|
const final = await integration.run({
|
|
488
430
|
name: "merger",
|
|
489
431
|
maxIterations: 1,
|
|
490
|
-
agent:
|
|
432
|
+
agent: shipyard.codex(shipyard.CODEX_MODELS.strong),
|
|
491
433
|
promptFile: "./.shipyard/merge-prompt.md",
|
|
492
434
|
promptArgs: {
|
|
493
435
|
TASK_ID: id,
|
|
@@ -503,7 +445,7 @@ for (let iteration = 0; iteration < 10; iteration++) {
|
|
|
503
445
|
const finalReview = await integration.run({
|
|
504
446
|
name: "reviewer",
|
|
505
447
|
maxIterations: 1,
|
|
506
|
-
agent:
|
|
448
|
+
agent: shipyard.codex(shipyard.CODEX_MODELS.strong),
|
|
507
449
|
promptFile: "./.shipyard/review-prompt.md",
|
|
508
450
|
promptArgs: {
|
|
509
451
|
TASK_ID: id,
|
|
@@ -7,55 +7,6 @@ import { docker } from "@snappedly-tools/shipyard/sandboxes/docker";
|
|
|
7
7
|
|
|
8
8
|
if (process.loadEnvFile && existsSync(".shipyard/.env"))
|
|
9
9
|
process.loadEnvFile(".shipyard/.env");
|
|
10
|
-
type ModelRole = "routine" | "strong";
|
|
11
|
-
const CODEX_PROVIDER = true;
|
|
12
|
-
const agentFactory = shipyard.codex;
|
|
13
|
-
type AgentModel = Parameters<typeof agentFactory>[0];
|
|
14
|
-
const readRoleModel = (role: ModelRole): string | undefined => {
|
|
15
|
-
const envName = `SHIPYARD_${role.toUpperCase()}_MODEL`;
|
|
16
|
-
const model = process.env[envName];
|
|
17
|
-
if (model !== undefined && model.trim().length === 0)
|
|
18
|
-
throw new Error(`${envName} must not be empty`);
|
|
19
|
-
return model;
|
|
20
|
-
};
|
|
21
|
-
const roleModels = {
|
|
22
|
-
routine: readRoleModel("routine"),
|
|
23
|
-
strong: readRoleModel("strong"),
|
|
24
|
-
};
|
|
25
|
-
const CODEX_REASONING_EFFORTS = shipyard.CODEX_REASONING_EFFORTS;
|
|
26
|
-
type CodexReasoningEffort = shipyard.CodexReasoningEffort;
|
|
27
|
-
const readCodexReasoningEffort = (
|
|
28
|
-
role: ModelRole,
|
|
29
|
-
): CodexReasoningEffort | undefined => {
|
|
30
|
-
if (!CODEX_PROVIDER) return undefined;
|
|
31
|
-
const envName = `SHIPYARD_CODEX_${role.toUpperCase()}_REASONING_EFFORT`;
|
|
32
|
-
const effort = process.env[envName]?.trim();
|
|
33
|
-
if (!effort) return undefined;
|
|
34
|
-
if (!(CODEX_REASONING_EFFORTS as readonly string[]).includes(effort))
|
|
35
|
-
throw new Error(
|
|
36
|
-
`${envName} must be one of ${CODEX_REASONING_EFFORTS.join(", ")}; received "${effort}"`,
|
|
37
|
-
);
|
|
38
|
-
return effort as CodexReasoningEffort;
|
|
39
|
-
};
|
|
40
|
-
const roleEfforts = {
|
|
41
|
-
routine: readCodexReasoningEffort("routine"),
|
|
42
|
-
strong: readCodexReasoningEffort("strong"),
|
|
43
|
-
};
|
|
44
|
-
const readCodexRoleModel = (role: ModelRole, defaultModel: AgentModel) => {
|
|
45
|
-
if (!CODEX_PROVIDER || typeof defaultModel === "string") return defaultModel;
|
|
46
|
-
const envName = `SHIPYARD_CODEX_${role.toUpperCase()}_MODEL`;
|
|
47
|
-
const model = process.env[envName]?.trim();
|
|
48
|
-
return model ? { ...defaultModel, model } : defaultModel;
|
|
49
|
-
};
|
|
50
|
-
const roleAgent = (role: ModelRole, defaultModel: AgentModel) => {
|
|
51
|
-
const model = roleModels[role] ?? readCodexRoleModel(role, defaultModel);
|
|
52
|
-
const effort = roleEfforts[role];
|
|
53
|
-
if (typeof model !== "string")
|
|
54
|
-
return effort === undefined
|
|
55
|
-
? agentFactory(model)
|
|
56
|
-
: agentFactory(model, { effort });
|
|
57
|
-
return agentFactory(model, { effort: effort ?? null });
|
|
58
|
-
};
|
|
59
10
|
const targetBranch = execFileSync("git", ["branch", "--show-current"], {
|
|
60
11
|
encoding: "utf8",
|
|
61
12
|
}).trim();
|
|
@@ -185,7 +136,7 @@ for (let iteration = 0; iteration < MAX_ITERATIONS; iteration++) {
|
|
|
185
136
|
: [issue.id]) {
|
|
186
137
|
await sandbox.run({
|
|
187
138
|
name: `triage #${ticketId}`,
|
|
188
|
-
agent:
|
|
139
|
+
agent: shipyard.codex(shipyard.CODEX_MODELS.strong),
|
|
189
140
|
maxIterations: 1,
|
|
190
141
|
promptFile: "./.shipyard/triage-prompt.md",
|
|
191
142
|
promptArgs: { TASK_ID: ticketId },
|
|
@@ -195,7 +146,7 @@ for (let iteration = 0; iteration < MAX_ITERATIONS; iteration++) {
|
|
|
195
146
|
const implement = await sandbox.run({
|
|
196
147
|
name: "implementer",
|
|
197
148
|
maxIterations: 1,
|
|
198
|
-
agent:
|
|
149
|
+
agent: shipyard.codex(shipyard.CODEX_MODELS.routine),
|
|
199
150
|
promptFile: "./.shipyard/implement-prompt.md",
|
|
200
151
|
promptArgs: {
|
|
201
152
|
TASK_ID: issue.id,
|
|
@@ -214,7 +165,7 @@ for (let iteration = 0; iteration < MAX_ITERATIONS; iteration++) {
|
|
|
214
165
|
const review = await sandbox.run({
|
|
215
166
|
name: "reviewer",
|
|
216
167
|
maxIterations: 1,
|
|
217
|
-
agent:
|
|
168
|
+
agent: shipyard.codex(shipyard.CODEX_MODELS.strong),
|
|
218
169
|
promptFile: "./.shipyard/review-prompt.md",
|
|
219
170
|
promptArgs: {
|
|
220
171
|
BRANCH: issue.branch,
|
|
@@ -7,55 +7,6 @@ import { docker } from "@snappedly-tools/shipyard/sandboxes/docker";
|
|
|
7
7
|
|
|
8
8
|
if (process.loadEnvFile && existsSync(".shipyard/.env"))
|
|
9
9
|
process.loadEnvFile(".shipyard/.env");
|
|
10
|
-
type ModelRole = "routine" | "strong";
|
|
11
|
-
const CODEX_PROVIDER = true;
|
|
12
|
-
const agentFactory = shipyard.codex;
|
|
13
|
-
type AgentModel = Parameters<typeof agentFactory>[0];
|
|
14
|
-
const readRoleModel = (role: ModelRole): string | undefined => {
|
|
15
|
-
const envName = `SHIPYARD_${role.toUpperCase()}_MODEL`;
|
|
16
|
-
const model = process.env[envName];
|
|
17
|
-
if (model !== undefined && model.trim().length === 0)
|
|
18
|
-
throw new Error(`${envName} must not be empty`);
|
|
19
|
-
return model;
|
|
20
|
-
};
|
|
21
|
-
const roleModels = {
|
|
22
|
-
routine: readRoleModel("routine"),
|
|
23
|
-
strong: readRoleModel("strong"),
|
|
24
|
-
};
|
|
25
|
-
const CODEX_REASONING_EFFORTS = shipyard.CODEX_REASONING_EFFORTS;
|
|
26
|
-
type CodexReasoningEffort = shipyard.CodexReasoningEffort;
|
|
27
|
-
const readCodexReasoningEffort = (
|
|
28
|
-
role: ModelRole,
|
|
29
|
-
): CodexReasoningEffort | undefined => {
|
|
30
|
-
if (!CODEX_PROVIDER) return undefined;
|
|
31
|
-
const envName = `SHIPYARD_CODEX_${role.toUpperCase()}_REASONING_EFFORT`;
|
|
32
|
-
const effort = process.env[envName]?.trim();
|
|
33
|
-
if (!effort) return undefined;
|
|
34
|
-
if (!(CODEX_REASONING_EFFORTS as readonly string[]).includes(effort))
|
|
35
|
-
throw new Error(
|
|
36
|
-
`${envName} must be one of ${CODEX_REASONING_EFFORTS.join(", ")}; received "${effort}"`,
|
|
37
|
-
);
|
|
38
|
-
return effort as CodexReasoningEffort;
|
|
39
|
-
};
|
|
40
|
-
const roleEfforts = {
|
|
41
|
-
routine: readCodexReasoningEffort("routine"),
|
|
42
|
-
strong: readCodexReasoningEffort("strong"),
|
|
43
|
-
};
|
|
44
|
-
const readCodexRoleModel = (role: ModelRole, defaultModel: AgentModel) => {
|
|
45
|
-
if (!CODEX_PROVIDER || typeof defaultModel === "string") return defaultModel;
|
|
46
|
-
const envName = `SHIPYARD_CODEX_${role.toUpperCase()}_MODEL`;
|
|
47
|
-
const model = process.env[envName]?.trim();
|
|
48
|
-
return model ? { ...defaultModel, model } : defaultModel;
|
|
49
|
-
};
|
|
50
|
-
const roleAgent = (role: ModelRole, defaultModel: AgentModel) => {
|
|
51
|
-
const model = roleModels[role] ?? readCodexRoleModel(role, defaultModel);
|
|
52
|
-
const effort = roleEfforts[role];
|
|
53
|
-
if (typeof model !== "string")
|
|
54
|
-
return effort === undefined
|
|
55
|
-
? agentFactory(model)
|
|
56
|
-
: agentFactory(model, { effort });
|
|
57
|
-
return agentFactory(model, { effort: effort ?? null });
|
|
58
|
-
};
|
|
59
10
|
const targetBranch = execFileSync("git", ["branch", "--show-current"], {
|
|
60
11
|
encoding: "utf8",
|
|
61
12
|
}).trim();
|
|
@@ -182,7 +133,7 @@ for (let iteration = 0; iteration < 3; iteration++) {
|
|
|
182
133
|
: [issue.id]) {
|
|
183
134
|
await sandbox.run({
|
|
184
135
|
name: `triage #${ticketId}`,
|
|
185
|
-
agent:
|
|
136
|
+
agent: shipyard.codex(shipyard.CODEX_MODELS.strong),
|
|
186
137
|
maxIterations: 1,
|
|
187
138
|
promptFile: "./.shipyard/triage-prompt.md",
|
|
188
139
|
promptArgs: { TASK_ID: ticketId },
|
|
@@ -191,7 +142,7 @@ for (let iteration = 0; iteration < 3; iteration++) {
|
|
|
191
142
|
}
|
|
192
143
|
const result = await sandbox.run({
|
|
193
144
|
name: "implementer",
|
|
194
|
-
agent:
|
|
145
|
+
agent: shipyard.codex(shipyard.CODEX_MODELS.routine),
|
|
195
146
|
maxIterations: 1,
|
|
196
147
|
promptFile: "./.shipyard/prompt.md",
|
|
197
148
|
promptArgs: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@snappedly-tools/shipyard",
|
|
3
|
-
"version": "0.7.0
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Run AI coding agents in isolated sandboxes",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -13,6 +13,14 @@
|
|
|
13
13
|
"./sandboxes/docker": {
|
|
14
14
|
"import": "./dist/sandboxes/docker.js",
|
|
15
15
|
"types": "./dist/sandboxes/docker.d.ts"
|
|
16
|
+
},
|
|
17
|
+
"./sandboxes/vercel": {
|
|
18
|
+
"import": "./dist/sandboxes/vercel.js",
|
|
19
|
+
"types": "./dist/sandboxes/vercel.d.ts"
|
|
20
|
+
},
|
|
21
|
+
"./sandboxes/no-sandbox": {
|
|
22
|
+
"import": "./dist/sandboxes/no-sandbox.js",
|
|
23
|
+
"types": "./dist/sandboxes/no-sandbox.d.ts"
|
|
16
24
|
}
|
|
17
25
|
},
|
|
18
26
|
"bin": {
|
|
@@ -82,6 +90,14 @@
|
|
|
82
90
|
"tsx": "^4.23.13",
|
|
83
91
|
"zod": "^4.6.5"
|
|
84
92
|
},
|
|
93
|
+
"peerDependencies": {
|
|
94
|
+
"@vercel/sandbox": ">=1.0.0"
|
|
95
|
+
},
|
|
96
|
+
"peerDependenciesMeta": {
|
|
97
|
+
"@vercel/sandbox": {
|
|
98
|
+
"optional": true
|
|
99
|
+
}
|
|
100
|
+
},
|
|
85
101
|
"files": [
|
|
86
102
|
"dist",
|
|
87
103
|
"LICENSE",
|
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
/** Result of executing a command inside a sandbox. */
|
|
2
|
-
interface ExecResult {
|
|
3
|
-
/** Collected standard output. */
|
|
4
|
-
readonly stdout: string;
|
|
5
|
-
/** Collected standard error. */
|
|
6
|
-
readonly stderr: string;
|
|
7
|
-
/** Process exit status. */
|
|
8
|
-
readonly exitCode: number;
|
|
9
|
-
}
|
|
10
|
-
/** Streams supplied when launching an interactive agent process. */
|
|
11
|
-
interface InteractiveExecOptions {
|
|
12
|
-
/** Input stream forwarded to the agent process. */
|
|
13
|
-
readonly stdin: NodeJS.ReadableStream;
|
|
14
|
-
/** Output stream receiving agent standard output. */
|
|
15
|
-
readonly stdout: NodeJS.WritableStream;
|
|
16
|
-
/** Output stream receiving agent standard error. */
|
|
17
|
-
readonly stderr: NodeJS.WritableStream;
|
|
18
|
-
/** Working directory inside Docker. */
|
|
19
|
-
readonly cwd?: string;
|
|
20
|
-
/** Abort signal that terminates the interactive process. */
|
|
21
|
-
readonly signal?: AbortSignal;
|
|
22
|
-
}
|
|
23
|
-
/** Handle to a running isolated sandbox. Docker implements this contract. */
|
|
24
|
-
interface IsolatedSandboxHandle {
|
|
25
|
-
/** Absolute Git workspace path inside Docker. */
|
|
26
|
-
readonly worktreePath: string;
|
|
27
|
-
/**
|
|
28
|
-
* Execute a command in Docker. Deliver `onLine` as output arrives so idle
|
|
29
|
-
* timeouts and live feedback work; buffered delivery does not satisfy this
|
|
30
|
-
* contract. Pipe `stdin` to the child rather than passing it as an argument.
|
|
31
|
-
*/
|
|
32
|
-
exec(command: string, options?: {
|
|
33
|
-
/** Live output callback. */
|
|
34
|
-
onLine?: (line: string) => void;
|
|
35
|
-
/** Working directory inside Docker. */
|
|
36
|
-
cwd?: string;
|
|
37
|
-
/** Execute as root when supported. */
|
|
38
|
-
sudo?: boolean;
|
|
39
|
-
/** Input piped to the child process. */
|
|
40
|
-
stdin?: string;
|
|
41
|
-
/** Abort signal that terminates the command. */
|
|
42
|
-
signal?: AbortSignal;
|
|
43
|
-
/** Maximum combined output bytes before termination. */
|
|
44
|
-
maxOutputBytes?: number;
|
|
45
|
-
}): Promise<ExecResult>;
|
|
46
|
-
/** Launch an interactive process and terminate it when `signal` aborts. */
|
|
47
|
-
interactiveExec?(args: string[], options: InteractiveExecOptions): Promise<{
|
|
48
|
-
exitCode: number;
|
|
49
|
-
}>;
|
|
50
|
-
/** Copy a file or directory from the host into Docker. */
|
|
51
|
-
copyIn(hostPath: string, sandboxPath: string): Promise<void>;
|
|
52
|
-
/** Copy a file from Docker to the host. */
|
|
53
|
-
copyFileOut(sandboxPath: string, hostPath: string): Promise<void>;
|
|
54
|
-
/** Tear down the container. */
|
|
55
|
-
close(): Promise<void>;
|
|
56
|
-
}
|
|
57
|
-
/** File transfer shape used by agent session storage. */
|
|
58
|
-
interface SessionTransferHandle {
|
|
59
|
-
/** Absolute Git workspace path inside Docker. */
|
|
60
|
-
readonly worktreePath: string;
|
|
61
|
-
/** Run a command in the sandbox. */
|
|
62
|
-
exec: IsolatedSandboxHandle["exec"];
|
|
63
|
-
/** Launch an interactive command when available. */
|
|
64
|
-
interactiveExec?: IsolatedSandboxHandle["interactiveExec"];
|
|
65
|
-
/** Copy one host file into the sandbox. */
|
|
66
|
-
copyFileIn(hostPath: string, sandboxPath: string): Promise<void>;
|
|
67
|
-
/** Copy one sandbox file to the host. */
|
|
68
|
-
copyFileOut(sandboxPath: string, hostPath: string): Promise<void>;
|
|
69
|
-
/** Tear down the sandbox. */
|
|
70
|
-
close(): Promise<void>;
|
|
71
|
-
}
|
|
72
|
-
/** Inputs to Docker sandbox creation. */
|
|
73
|
-
interface IsolatedCreateOptions {
|
|
74
|
-
/** Original repository path used to derive the image name; never mounted. */
|
|
75
|
-
readonly hostRepoPath?: string;
|
|
76
|
-
/** Environment injected into the Docker container. */
|
|
77
|
-
readonly env: Record<string, string>;
|
|
78
|
-
}
|
|
79
|
-
/** Configuration for the isolated Docker provider contract. */
|
|
80
|
-
interface IsolatedSandboxProviderConfig {
|
|
81
|
-
/** Human-readable provider name. */
|
|
82
|
-
readonly name: string;
|
|
83
|
-
/** Provider environment merged into sandbox startup. */
|
|
84
|
-
readonly env?: Record<string, string>;
|
|
85
|
-
/** Start a sandbox and return its command and file-transfer handle. */
|
|
86
|
-
readonly create: (options: IsolatedCreateOptions) => Promise<IsolatedSandboxHandle>;
|
|
87
|
-
}
|
|
88
|
-
/** Docker's isolated filesystem provider contract. */
|
|
89
|
-
interface IsolatedSandboxProvider {
|
|
90
|
-
/** Isolated filesystem discriminator. */
|
|
91
|
-
readonly tag: "isolated";
|
|
92
|
-
/** Human-readable provider name. */
|
|
93
|
-
readonly name: string;
|
|
94
|
-
/** Environment variables injected into Docker. */
|
|
95
|
-
readonly env: Record<string, string>;
|
|
96
|
-
/** Start a sandbox. */
|
|
97
|
-
readonly create: (options: IsolatedCreateOptions) => Promise<IsolatedSandboxHandle>;
|
|
98
|
-
}
|
|
99
|
-
/** Provider accepted by Shipyard's Docker execution path. */
|
|
100
|
-
type SandboxProvider = IsolatedSandboxProvider;
|
|
101
|
-
/** Create a temporary branch and merge its commits back to host HEAD. */
|
|
102
|
-
interface MergeToHeadBranchStrategy {
|
|
103
|
-
/** Branch strategy discriminator. */
|
|
104
|
-
readonly type: "merge-to-head";
|
|
105
|
-
}
|
|
106
|
-
/** Run on a caller-named branch. */
|
|
107
|
-
interface NamedBranchStrategy {
|
|
108
|
-
/** Branch strategy discriminator. */
|
|
109
|
-
readonly type: "branch";
|
|
110
|
-
/** Branch to create or reuse. */
|
|
111
|
-
readonly branch: string;
|
|
112
|
-
/** Starting ref for a new branch. */
|
|
113
|
-
readonly baseBranch?: string;
|
|
114
|
-
}
|
|
115
|
-
/** Supported Docker branch strategies. */
|
|
116
|
-
type BranchStrategy = MergeToHeadBranchStrategy | NamedBranchStrategy;
|
|
117
|
-
/** Construct the isolated provider contract used by Docker. */
|
|
118
|
-
declare const createIsolatedSandboxProvider: (config: IsolatedSandboxProviderConfig) => IsolatedSandboxProvider;
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* User-facing mount configuration for Docker.
|
|
122
|
-
*
|
|
123
|
-
* Each entry describes a host directory to mount into the sandbox container.
|
|
124
|
-
*/
|
|
125
|
-
/** A single bind-mount descriptor for the Docker provider. */
|
|
126
|
-
interface MountConfig {
|
|
127
|
-
/**
|
|
128
|
-
* Path on the host. Supports:
|
|
129
|
-
* - Absolute paths (`/data/cache`)
|
|
130
|
-
* - Tilde-expanded paths (`~/data` → `<home>/data`)
|
|
131
|
-
* - Relative paths (`data` or `./data`) — resolved from `process.cwd()`
|
|
132
|
-
*/
|
|
133
|
-
readonly hostPath: string;
|
|
134
|
-
/**
|
|
135
|
-
* Path inside the sandbox container. Supports:
|
|
136
|
-
* - Absolute paths (`/mnt/data`)
|
|
137
|
-
* - Tilde-expanded paths (`~/.npm` → `/home/agent/.npm`) — expanded using the provider's sandbox home directory
|
|
138
|
-
* - Relative paths (`data` or `./data`) — resolved from the worktree directory (`/home/agent/workspace`)
|
|
139
|
-
*/
|
|
140
|
-
readonly sandboxPath: string;
|
|
141
|
-
/** Mount as read-only. Defaults to `false`. */
|
|
142
|
-
readonly readonly?: boolean;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
export { type BranchStrategy as B, type ExecResult as E, type IsolatedSandboxProvider as I, type MountConfig as M, type NamedBranchStrategy as N, type SessionTransferHandle as S, type SandboxProvider as a, type MergeToHeadBranchStrategy as b, type InteractiveExecOptions as c, type IsolatedCreateOptions as d, type IsolatedSandboxHandle as e, type IsolatedSandboxProviderConfig as f, createIsolatedSandboxProvider as g };
|