@elie-laloum/outpost 1.1.3 → 2.0.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/CHANGELOG.md +20 -0
- package/README.md +12 -6
- package/dist/cli/image.js +1 -1
- package/dist/cli/image.js.map +1 -1
- package/dist/cli/init-command.js +4 -3
- package/dist/cli/init-command.js.map +1 -1
- package/dist/cli/main.constants.d.ts +4 -10
- package/dist/cli/main.constants.js +4 -7
- package/dist/cli/main.constants.js.map +1 -1
- package/dist/cli/project-settings.js +8 -2
- package/dist/cli/project-settings.js.map +1 -1
- package/dist/cli/scaffold-files.d.ts +1 -1
- package/dist/cli/scaffold-files.js +26 -20
- package/dist/cli/scaffold-files.js.map +1 -1
- package/dist/cli/scaffold-validation.js +2 -5
- package/dist/cli/scaffold-validation.js.map +1 -1
- package/dist/cli/scaffold.constants.d.ts +0 -2
- package/dist/cli/scaffold.constants.js +2 -13
- package/dist/cli/scaffold.constants.js.map +1 -1
- package/dist/cli/scaffold.d.ts +1 -1
- package/dist/cli/scaffold.js +37 -29
- package/dist/cli/scaffold.js.map +1 -1
- package/dist/cli/scaffold.types.d.ts +3 -5
- package/dist/cli/scaffold.types.js.map +1 -1
- package/dist/cli/starters.d.ts +1 -2
- package/dist/cli/starters.js +42 -30
- package/dist/cli/starters.js.map +1 -1
- package/dist/index.d.ts +0 -5
- package/dist/index.js +0 -2
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/binary-process.d.ts +3 -0
- package/dist/infrastructure/binary-process.js +53 -0
- package/dist/infrastructure/binary-process.js.map +1 -0
- package/dist/infrastructure/binary-process.types.d.ts +5 -0
- package/dist/infrastructure/binary-process.types.js +2 -0
- package/dist/infrastructure/binary-process.types.js.map +1 -0
- package/dist/infrastructure/transfer-copy.d.ts +3 -0
- package/dist/infrastructure/transfer-copy.js +51 -0
- package/dist/infrastructure/transfer-copy.js.map +1 -0
- package/dist/providers/container-archive.d.ts +3 -0
- package/dist/providers/container-archive.js +27 -0
- package/dist/providers/container-archive.js.map +1 -0
- package/dist/providers/container-command.js +3 -3
- package/dist/providers/container-command.js.map +1 -1
- package/dist/providers/container-files.d.ts +2 -1
- package/dist/providers/container-files.js +100 -11
- package/dist/providers/container-files.js.map +1 -1
- package/dist/providers/container.js +11 -2
- package/dist/providers/container.js.map +1 -1
- package/package.json +1 -1
- package/dist/adapters/backlogs/backlog.constants.d.ts +0 -4
- package/dist/adapters/backlogs/backlog.constants.js +0 -5
- package/dist/adapters/backlogs/backlog.constants.js.map +0 -1
- package/dist/adapters/backlogs/beads-adapter.d.ts +0 -4
- package/dist/adapters/backlogs/beads-adapter.js +0 -31
- package/dist/adapters/backlogs/beads-adapter.js.map +0 -1
- package/dist/adapters/backlogs/cli.d.ts +0 -3
- package/dist/adapters/backlogs/cli.js +0 -20
- package/dist/adapters/backlogs/cli.js.map +0 -1
- package/dist/adapters/backlogs/github-adapter.d.ts +0 -4
- package/dist/adapters/backlogs/github-adapter.js +0 -28
- package/dist/adapters/backlogs/github-adapter.js.map +0 -1
- package/dist/adapters/backlogs/issue.d.ts +0 -2
- package/dist/adapters/backlogs/issue.js +0 -13
- package/dist/adapters/backlogs/issue.js.map +0 -1
- package/dist/adapters/backlogs/settings.types.d.ts +0 -5
- package/dist/adapters/backlogs/settings.types.js +0 -2
- package/dist/adapters/backlogs/settings.types.js.map +0 -1
- package/dist/application/campaign-integration.d.ts +0 -2
- package/dist/application/campaign-integration.js +0 -44
- package/dist/application/campaign-integration.js.map +0 -1
- package/dist/application/campaign-planner.d.ts +0 -3
- package/dist/application/campaign-planner.js +0 -35
- package/dist/application/campaign-planner.js.map +0 -1
- package/dist/application/campaign-worker.d.ts +0 -3
- package/dist/application/campaign-worker.js +0 -54
- package/dist/application/campaign-worker.js.map +0 -1
- package/dist/application/campaign.constants.d.ts +0 -7
- package/dist/application/campaign.constants.js +0 -8
- package/dist/application/campaign.constants.js.map +0 -1
- package/dist/application/campaign.d.ts +0 -3
- package/dist/application/campaign.js +0 -96
- package/dist/application/campaign.js.map +0 -1
- package/dist/application/campaign.types.d.ts +0 -43
- package/dist/application/campaign.types.js +0 -2
- package/dist/application/campaign.types.js.map +0 -1
- package/dist/domain/backlog.d.ts +0 -3
- package/dist/domain/backlog.js +0 -23
- package/dist/domain/backlog.js.map +0 -1
- package/dist/domain/backlog.types.d.ts +0 -15
- package/dist/domain/backlog.types.js +0 -2
- package/dist/domain/backlog.types.js.map +0 -1
- package/dist/providers/backlogs.d.ts +0 -3
- package/dist/providers/backlogs.js +0 -3
- package/dist/providers/backlogs.js.map +0 -1
|
@@ -1,16 +1,105 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { lstat, mkdir, mkdtemp } from "node:fs/promises";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { basename, dirname, join, posix, resolve } from "node:path";
|
|
5
|
+
import { invariant, OutpostError } from "../domain/errors.js";
|
|
6
|
+
import { quote } from "../infrastructure/process.js";
|
|
7
|
+
import { copyTransfer, removeTransferDirectory, transferDestination, } from "../infrastructure/transfer-copy.js";
|
|
8
|
+
import { transfer } from "../infrastructure/transfer.js";
|
|
9
|
+
import { containerArchive } from "./container-archive.js";
|
|
10
|
+
export function containerFiles(runtime, archive = containerArchive) {
|
|
11
|
+
const { call, name } = runtime;
|
|
4
12
|
return {
|
|
5
|
-
|
|
6
|
-
options
|
|
7
|
-
|
|
8
|
-
|
|
13
|
+
upload(source, destination, options = {}) {
|
|
14
|
+
return transfer(options, async (signal) => {
|
|
15
|
+
if (runtime.isClosed())
|
|
16
|
+
throw new OutpostError("provider", "Container sandbox is closed");
|
|
17
|
+
const absolute = resolve(source);
|
|
18
|
+
const scratch = `/tmp/outpost-transfer-${randomUUID()}`;
|
|
19
|
+
const entry = basename(absolute);
|
|
20
|
+
invariant(entry, "Upload a directory's contents using a non-root path");
|
|
21
|
+
const contents = /[\\/]\.$/.test(source);
|
|
22
|
+
await call(["exec", name, "mkdir", "-m", "700", scratch], { signal });
|
|
23
|
+
try {
|
|
24
|
+
await archive(runtime, {
|
|
25
|
+
executable: "tar",
|
|
26
|
+
arguments: ["-cf", "-", "-C", dirname(absolute), "--", entry],
|
|
27
|
+
}, {
|
|
28
|
+
executable: "tar",
|
|
29
|
+
arguments: [
|
|
30
|
+
"-xpf",
|
|
31
|
+
"-",
|
|
32
|
+
"--ignore-zeros",
|
|
33
|
+
"--no-same-owner",
|
|
34
|
+
"-C",
|
|
35
|
+
scratch,
|
|
36
|
+
],
|
|
37
|
+
}, true, signal);
|
|
38
|
+
await call([
|
|
39
|
+
"exec",
|
|
40
|
+
name,
|
|
41
|
+
"sh",
|
|
42
|
+
"-c",
|
|
43
|
+
`mkdir -p ${quote(posix.dirname(destination))} && cp -a -- ${quote(posix.join(scratch, entry) + (contents ? "/." : ""))} ${quote(destination)}`,
|
|
44
|
+
], { signal });
|
|
45
|
+
}
|
|
46
|
+
finally {
|
|
47
|
+
await call([
|
|
48
|
+
"exec",
|
|
49
|
+
name,
|
|
50
|
+
"sh",
|
|
51
|
+
"-c",
|
|
52
|
+
`chmod -R u+rwX ${quote(scratch)} && rm -rf -- ${quote(scratch)}`,
|
|
53
|
+
]);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
9
56
|
},
|
|
10
|
-
|
|
11
|
-
options
|
|
12
|
-
|
|
13
|
-
|
|
57
|
+
download(source, destination, options = {}) {
|
|
58
|
+
return transfer(options, async (signal) => {
|
|
59
|
+
if (runtime.isClosed())
|
|
60
|
+
throw new OutpostError("provider", "Container sandbox is closed");
|
|
61
|
+
await transferDestination(destination);
|
|
62
|
+
const absolute = posix.resolve(runtime.root, source);
|
|
63
|
+
const entry = posix.basename(absolute);
|
|
64
|
+
invariant(entry, "Download a directory's contents using a non-root path");
|
|
65
|
+
const scratch = await mkdtemp(join(tmpdir(), "outpost-transfer-"));
|
|
66
|
+
try {
|
|
67
|
+
await archive(runtime, {
|
|
68
|
+
executable: "tar",
|
|
69
|
+
arguments: [
|
|
70
|
+
"-xpf",
|
|
71
|
+
"-",
|
|
72
|
+
"--ignore-zeros",
|
|
73
|
+
"--no-same-owner",
|
|
74
|
+
"-C",
|
|
75
|
+
scratch,
|
|
76
|
+
],
|
|
77
|
+
}, {
|
|
78
|
+
executable: "tar",
|
|
79
|
+
arguments: [
|
|
80
|
+
"-cf",
|
|
81
|
+
"-",
|
|
82
|
+
"-C",
|
|
83
|
+
posix.dirname(absolute),
|
|
84
|
+
"--",
|
|
85
|
+
entry,
|
|
86
|
+
],
|
|
87
|
+
}, false, signal);
|
|
88
|
+
const existing = await lstat(destination).catch((cause) => {
|
|
89
|
+
if (cause.code === "ENOENT")
|
|
90
|
+
return undefined;
|
|
91
|
+
throw cause;
|
|
92
|
+
});
|
|
93
|
+
const target = existing?.isDirectory() && !source.endsWith("/.")
|
|
94
|
+
? join(destination, entry)
|
|
95
|
+
: destination;
|
|
96
|
+
await mkdir(dirname(target), { recursive: true });
|
|
97
|
+
await copyTransfer(join(scratch, entry), target, signal);
|
|
98
|
+
}
|
|
99
|
+
finally {
|
|
100
|
+
await removeTransferDirectory(scratch);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
14
103
|
},
|
|
15
104
|
};
|
|
16
105
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"container-files.js","sourceRoot":"","sources":["../../src/providers/container-files.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"container-files.js","sourceRoot":"","sources":["../../src/providers/container-files.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { lstat, mkdir, mkdtemp } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { basename, dirname, join, posix, resolve } from \"node:path\";\nimport type { SandboxLease } from \"../domain/sandbox.types.ts\";\nimport { invariant, OutpostError } from \"../domain/errors.ts\";\nimport { quote } from \"../infrastructure/process.ts\";\nimport {\n copyTransfer,\n removeTransferDirectory,\n transferDestination,\n} from \"../infrastructure/transfer-copy.ts\";\nimport { transfer } from \"../infrastructure/transfer.ts\";\nimport { containerArchive } from \"./container-archive.ts\";\nimport type { ContainerRuntime } from \"./container.types.ts\";\n\nexport function containerFiles(\n runtime: ContainerRuntime,\n archive = containerArchive,\n): Pick<SandboxLease, \"upload\" | \"download\"> {\n const { call, name } = runtime;\n return {\n upload(source, destination, options = {}) {\n return transfer(options, async (signal) => {\n if (runtime.isClosed())\n throw new OutpostError(\"provider\", \"Container sandbox is closed\");\n const absolute = resolve(source);\n const scratch = `/tmp/outpost-transfer-${randomUUID()}`;\n const entry = basename(absolute);\n invariant(entry, \"Upload a directory's contents using a non-root path\");\n const contents = /[\\\\/]\\.$/.test(source);\n await call([\"exec\", name, \"mkdir\", \"-m\", \"700\", scratch], { signal });\n try {\n await archive(\n runtime,\n {\n executable: \"tar\",\n arguments: [\"-cf\", \"-\", \"-C\", dirname(absolute), \"--\", entry],\n },\n {\n executable: \"tar\",\n arguments: [\n \"-xpf\",\n \"-\",\n \"--ignore-zeros\",\n \"--no-same-owner\",\n \"-C\",\n scratch,\n ],\n },\n true,\n signal,\n );\n await call(\n [\n \"exec\",\n name,\n \"sh\",\n \"-c\",\n `mkdir -p ${quote(posix.dirname(destination))} && cp -a -- ${quote(posix.join(scratch, entry) + (contents ? \"/.\" : \"\"))} ${quote(destination)}`,\n ],\n { signal },\n );\n } finally {\n await call([\n \"exec\",\n name,\n \"sh\",\n \"-c\",\n `chmod -R u+rwX ${quote(scratch)} && rm -rf -- ${quote(scratch)}`,\n ]);\n }\n });\n },\n download(source, destination, options = {}) {\n return transfer(options, async (signal) => {\n if (runtime.isClosed())\n throw new OutpostError(\"provider\", \"Container sandbox is closed\");\n await transferDestination(destination);\n const absolute = posix.resolve(runtime.root, source);\n const entry = posix.basename(absolute);\n invariant(\n entry,\n \"Download a directory's contents using a non-root path\",\n );\n const scratch = await mkdtemp(join(tmpdir(), \"outpost-transfer-\"));\n try {\n await archive(\n runtime,\n {\n executable: \"tar\",\n arguments: [\n \"-xpf\",\n \"-\",\n \"--ignore-zeros\",\n \"--no-same-owner\",\n \"-C\",\n scratch,\n ],\n },\n {\n executable: \"tar\",\n arguments: [\n \"-cf\",\n \"-\",\n \"-C\",\n posix.dirname(absolute),\n \"--\",\n entry,\n ],\n },\n false,\n signal,\n );\n const existing = await lstat(destination).catch(\n (cause: NodeJS.ErrnoException) => {\n if (cause.code === \"ENOENT\") return undefined;\n throw cause;\n },\n );\n const target =\n existing?.isDirectory() && !source.endsWith(\"/.\")\n ? join(destination, entry)\n : destination;\n await mkdir(dirname(target), { recursive: true });\n await copyTransfer(join(scratch, entry), target, signal);\n } finally {\n await removeTransferDirectory(scratch);\n }\n });\n },\n };\n}\n"]}
|
|
@@ -101,7 +101,7 @@ export function containerProvider(engine, options = {}, executor = executeProces
|
|
|
101
101
|
name,
|
|
102
102
|
"sh",
|
|
103
103
|
"-c",
|
|
104
|
-
"command -v setsid >/dev/null && command -v kill >/dev/null",
|
|
104
|
+
"command -v setsid >/dev/null && command -v kill >/dev/null && command -v tar >/dev/null && command -v cp >/dev/null",
|
|
105
105
|
]);
|
|
106
106
|
}
|
|
107
107
|
catch (cause) {
|
|
@@ -134,7 +134,16 @@ export function containerProvider(engine, options = {}, executor = executeProces
|
|
|
134
134
|
call,
|
|
135
135
|
isClosed: () => closed,
|
|
136
136
|
}),
|
|
137
|
-
...containerFiles(
|
|
137
|
+
...containerFiles({
|
|
138
|
+
engine,
|
|
139
|
+
config,
|
|
140
|
+
executor,
|
|
141
|
+
root,
|
|
142
|
+
name,
|
|
143
|
+
env,
|
|
144
|
+
call,
|
|
145
|
+
isClosed: () => closed,
|
|
146
|
+
}),
|
|
138
147
|
release,
|
|
139
148
|
};
|
|
140
149
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"container.js","sourceRoot":"","sources":["../../src/providers/container.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAErC,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAEhD,OAAO,EACL,cAAc,EACd,KAAK,EACL,cAAc,GACf,MAAM,8BAA8B,CAAC;AAEtC,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAK7D,MAAM,UAAU,SAAS,CAAC,UAAkB;IAC1C,OAAO,WACL,QAAQ,CAAC,UAAU,CAAC;SACjB,WAAW,EAAE;SACb,OAAO,CAAC,eAAe,EAAE,GAAG,CAAC,IAAI,WACtC,EAAE,CAAC;AACL,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,MAAuB,EACvB,UAA4B,EAAE,EAC9B,WAAqB,cAAc,EACnC,WAA4B,OAAO,CAAC,QAAQ;IAE5C,MAAM,MAAM,GAAG,EAAE,GAAG,OAAO,EAAE,CAAC;IAC9B,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS;QAC3B,SAAS,CACP,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,IAAI,GAAG,CAAC,EAC/C,uBAAuB,CACxB,CAAC;IACJ,IAAI,MAAM,CAAC,QAAQ,KAAK,SAAS;QAC/B,SAAS,CACP,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,QAAQ,CAAC;YACnC,MAAM,CAAC,QAAQ,IAAI,iBAAiB,CAAC,eAAe,EACtD,8BAA8B,CAC/B,CAAC;IACJ,OAAO;QACL,IAAI,EAAE,MAAM;QACZ,SAAS,EAAE,SAAS;QACpB,SAAS,EAAE,EAAE,GAAG,MAAM,CAAC,SAAS,EAAE;QAClC,KAAK,CAAC,OAAO,CAAC,OAAO;YACnB,OAAO,CAAC,MAAM,EAAE,cAAc,EAAE,CAAC;YACjC,MAAM,IAAI,GAAG,WAAW,UAAU,EAAE,EAAE,CAAC;YACvC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,SAAS,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;YAC5D,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,IAAI;gBAC1B,GAAG,EAAE,OAAO,CAAC,MAAM,EAAE,EAAE,IAAI,iBAAiB,CAAC,GAAG;gBAChD,GAAG,EAAE,OAAO,CAAC,MAAM,EAAE,EAAE,IAAI,iBAAiB,CAAC,GAAG;aACjD,CAAC;YACF,SAAS,CACP,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC;gBACxB,IAAI,CAAC,GAAG,IAAI,CAAC;gBACb,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC;gBAC1B,IAAI,CAAC,GAAG,IAAI,CAAC,EACf,wBAAwB,CACzB,CAAC;YACF,MAAM,IAAI,GAAG,CAAC,IAAuB,EAAE,QAA0B,EAAE,EAAE,EAAE,CACrE,cAAc,CACZ;gBACE,UAAU,EAAE,MAAM;gBAClB,SAAS,EAAE,IAAI;gBACf,UAAU,EAAE,iBAAiB,CAAC,UAAU;gBACxC,GAAG,KAAK;aACT,EACD,QAAQ,CACT,CAAC;YACJ,MAAM,kBAAkB,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;YACtE,MAAM,IAAI,GAAG,iBAAiB,CAAC,IAAI,EACjC,IAAI,GAAG,iBAAiB,CAAC,IAAI,CAAC;YAChC,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,MAAM,eAAe,CACzD,OAAO,EACP,MAAM,EACN,QAAQ,EACR,IAAI,EACJ,IAAI,CACL,CAAC;YACF,MAAM,IAAI,GAAG,aAAa,CAAC;gBACzB,MAAM;gBACN,MAAM;gBACN,IAAI;gBACJ,IAAI;gBACJ,IAAI;gBACJ,KAAK;gBACL,OAAO;gBACP,WAAW;aACZ,CAAC,CAAC;YACH,IAAI,MAAM,GAAG,KAAK,EAChB,SAAoC,CAAC;YACvC,IAAI,UAAU,GAAG,GAAG,EAAE,GAAE,CAAC,CAAC;YAC1B,MAAM,OAAO,GAAG,GAAkB,EAAE;gBAClC,MAAM,GAAG,IAAI,CAAC;gBACd,SAAS,KAAK,IAAI,CAAC,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;qBACxC,IAAI,CAAC,GAAG,EAAE;oBACT,UAAU,EAAE,CAAC;gBACf,CAAC,CAAC;qBACD,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;oBACf,SAAS,GAAG,SAAS,CAAC;oBACtB,MAAM,KAAK,CAAC;gBACd,CAAC,CAAC,CAAC;gBACL,OAAO,SAAS,CAAC;YACnB,CAAC,CAAC;YACF,IAAI,CAAC;gBACH,MAAM,IAAI,CAAC,IAAI,EAAE;oBACf,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;iBACtD,CAAC,CAAC;gBACH,MAAM,IAAI,CACR,CAAC,OAAO,EAAE,IAAI,CAAC,EACf,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CACjD,CAAC;gBACF,KAAK,MAAM,MAAM,IAAI,WAAW;oBAC9B,MAAM,IAAI,CAAC;wBACT,MAAM;wBACN,QAAQ;wBACR,KAAK;wBACL,IAAI;wBACJ,IAAI;wBACJ,IAAI;wBACJ,YAAY,KAAK,CAAC,MAAM,CAAC,aAAa,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,IAAI,KAAK,CAAC,MAAM,CAAC,EAAE;qBAC9E,CAAC,CAAC;gBACL,IAAI,WAAW,CAAC,IAAI;oBAClB,MAAM,IAAI,CAAC;wBACT,MAAM;wBACN,QAAQ;wBACR,KAAK;wBACL,IAAI;wBACJ,OAAO;wBACP,GAAG,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE;wBACzB,IAAI;qBACL,CAAC,CAAC;gBACL,MAAM,IAAI,CAAC;oBACT,MAAM;oBACN,IAAI;oBACJ,IAAI;oBACJ,IAAI;oBACJ,4DAA4D;iBAC7D,CAAC,CAAC;YACL,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAI,CAAC;oBACH,MAAM,OAAO,EAAE,CAAC;gBAClB,CAAC;gBAAC,OAAO,OAAO,EAAE,CAAC;oBACjB,MAAM,IAAI,cAAc,CACtB,CAAC,KAAK,EAAE,OAAO,CAAC,EAChB,yCAAyC,CAC1C,CAAC;gBACJ,CAAC;gBACD,MAAM,KAAK,CAAC;YACd,CAAC;YACD,UAAU,GAAG,eAAe,CAAC,OAAO,EAAE,GAAG,EAAE;gBACzC,IAAI,CAAC,MAAM;oBACT,YAAY,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,EAAE;wBAC5C,OAAO,EAAE,iBAAiB,CAAC,SAAS;wBACpC,KAAK,EAAE,QAAQ;wBACf,WAAW,EAAE,IAAI;qBAClB,CAAC,CAAC;YACP,CAAC,CAAC,CAAC;YACH,OAAO;gBACL,IAAI;gBACJ,IAAI;gBACJ,MAAM,EAAE,gBAAgB,CAAC;oBACvB,MAAM;oBACN,MAAM;oBACN,QAAQ;oBACR,IAAI;oBACJ,IAAI;oBACJ,GAAG;oBACH,IAAI;oBACJ,QAAQ,EAAE,GAAG,EAAE,CAAC,MAAM;iBACvB,CAAC;gBACF,GAAG,cAAc,CAAC,IAAI,EAAE,IAAI,CAAC;gBAC7B,OAAO;aACR,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC","sourcesContent":["import { execFileSync } from \"node:child_process\";\nimport { randomUUID } from \"node:crypto\";\nimport { basename } from \"node:path\";\nimport type { Command } from \"../domain/command.types.ts\";\nimport { invariant } from \"../domain/errors.ts\";\nimport type { SandboxProvider } from \"../domain/sandbox.types.ts\";\nimport {\n executeProcess,\n quote,\n requireSuccess,\n} from \"../infrastructure/process.ts\";\nimport type { Executor } from \"../infrastructure/process.types.ts\";\nimport { registerCleanup } from \"../infrastructure/shutdown.ts\";\nimport { containerCommand } from \"./container-command.ts\";\nimport { containerFiles } from \"./container-files.ts\";\nimport { containerMounts } from \"./container-mounts.ts\";\nimport { containerPlan } from \"./container-plan.ts\";\nimport { containerPreflight } from \"./container-preflight.ts\";\nimport { containerDefaults } from \"./container.constants.ts\";\nimport type { ContainerEngine, ContainerOptions } from \"./container.types.ts\";\n\nexport type { ContainerOptions } from \"./container.types.ts\";\n\nexport function imageName(repository: string): string {\n return `outpost:${\n basename(repository)\n .toLowerCase()\n .replace(/[^a-z0-9_.-]/g, \"-\") || \"workspace\"\n }`;\n}\n\nexport function containerProvider(\n engine: ContainerEngine,\n options: ContainerOptions = {},\n executor: Executor = executeProcess,\n platform: NodeJS.Platform = process.platform,\n): SandboxProvider {\n const config = { ...options };\n if (config.cpus !== undefined)\n invariant(\n Number.isFinite(config.cpus) && config.cpus > 0,\n \"cpus must be positive\",\n );\n if (config.memoryMb !== undefined)\n invariant(\n Number.isSafeInteger(config.memoryMb) &&\n config.memoryMb >= containerDefaults.minimumMemoryMb,\n \"memoryMb must be at least 64\",\n );\n return {\n name: engine,\n placement: \"mounted\",\n variables: { ...config.variables },\n async acquire(context) {\n context.signal?.throwIfAborted();\n const name = `outpost-${randomUUID()}`;\n const image = config.image ?? imageName(context.repository);\n const user = config.user ?? {\n uid: process.getuid?.() ?? containerDefaults.uid,\n gid: process.getgid?.() ?? containerDefaults.gid,\n };\n invariant(\n Number.isInteger(user.uid) &&\n user.uid >= 0 &&\n Number.isInteger(user.gid) &&\n user.gid >= 0,\n \"Invalid container user\",\n );\n const call = (args: readonly string[], extra: Partial<Command> = {}) =>\n requireSuccess(\n {\n executable: engine,\n arguments: args,\n deadlineMs: containerDefaults.deadlineMs,\n ...extra,\n },\n executor,\n );\n await containerPreflight(engine, platform, call, config, image, user);\n const root = containerDefaults.root,\n home = containerDefaults.home;\n const { env, volumes, fileParents } = await containerMounts(\n context,\n config,\n platform,\n root,\n home,\n );\n const args = containerPlan({\n config,\n engine,\n user,\n root,\n name,\n image,\n volumes,\n fileParents,\n });\n let closed = false,\n releasing: Promise<void> | undefined;\n let unregister = () => {};\n const release = (): Promise<void> => {\n closed = true;\n releasing ??= call([\"rm\", \"--force\", name])\n .then(() => {\n unregister();\n })\n .catch((error) => {\n releasing = undefined;\n throw error;\n });\n return releasing;\n };\n try {\n await call(args, {\n ...(context.signal ? { signal: context.signal } : {}),\n });\n await call(\n [\"start\", name],\n context.signal ? { signal: context.signal } : {},\n );\n for (const parent of fileParents)\n await call([\n \"exec\",\n \"--user\",\n \"0:0\",\n name,\n \"sh\",\n \"-c\",\n `mkdir -p ${quote(parent)} && chown ${user.uid}:${user.gid} ${quote(parent)}`,\n ]);\n if (fileParents.size)\n await call([\n \"exec\",\n \"--user\",\n \"0:0\",\n name,\n \"chown\",\n `${user.uid}:${user.gid}`,\n home,\n ]);\n await call([\n \"exec\",\n name,\n \"sh\",\n \"-c\",\n \"command -v setsid >/dev/null && command -v kill >/dev/null\",\n ]);\n } catch (cause) {\n try {\n await release();\n } catch (cleanup) {\n throw new AggregateError(\n [cause, cleanup],\n \"Sandbox provisioning and cleanup failed\",\n );\n }\n throw cause;\n }\n unregister = registerCleanup(release, () => {\n if (!closed)\n execFileSync(engine, [\"rm\", \"--force\", name], {\n timeout: containerDefaults.cleanupMs,\n stdio: \"ignore\",\n windowsHide: true,\n });\n });\n return {\n root,\n home,\n invoke: containerCommand({\n engine,\n config,\n executor,\n root,\n name,\n env,\n call,\n isClosed: () => closed,\n }),\n ...containerFiles(call, name),\n release,\n };\n },\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"container.js","sourceRoot":"","sources":["../../src/providers/container.ts"],"names":[],"mappings":"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","sourcesContent":["import { execFileSync } from \"node:child_process\";\nimport { randomUUID } from \"node:crypto\";\nimport { basename } from \"node:path\";\nimport type { Command } from \"../domain/command.types.ts\";\nimport { invariant } from \"../domain/errors.ts\";\nimport type { SandboxProvider } from \"../domain/sandbox.types.ts\";\nimport {\n executeProcess,\n quote,\n requireSuccess,\n} from \"../infrastructure/process.ts\";\nimport type { Executor } from \"../infrastructure/process.types.ts\";\nimport { registerCleanup } from \"../infrastructure/shutdown.ts\";\nimport { containerCommand } from \"./container-command.ts\";\nimport { containerFiles } from \"./container-files.ts\";\nimport { containerMounts } from \"./container-mounts.ts\";\nimport { containerPlan } from \"./container-plan.ts\";\nimport { containerPreflight } from \"./container-preflight.ts\";\nimport { containerDefaults } from \"./container.constants.ts\";\nimport type { ContainerEngine, ContainerOptions } from \"./container.types.ts\";\n\nexport type { ContainerOptions } from \"./container.types.ts\";\n\nexport function imageName(repository: string): string {\n return `outpost:${\n basename(repository)\n .toLowerCase()\n .replace(/[^a-z0-9_.-]/g, \"-\") || \"workspace\"\n }`;\n}\n\nexport function containerProvider(\n engine: ContainerEngine,\n options: ContainerOptions = {},\n executor: Executor = executeProcess,\n platform: NodeJS.Platform = process.platform,\n): SandboxProvider {\n const config = { ...options };\n if (config.cpus !== undefined)\n invariant(\n Number.isFinite(config.cpus) && config.cpus > 0,\n \"cpus must be positive\",\n );\n if (config.memoryMb !== undefined)\n invariant(\n Number.isSafeInteger(config.memoryMb) &&\n config.memoryMb >= containerDefaults.minimumMemoryMb,\n \"memoryMb must be at least 64\",\n );\n return {\n name: engine,\n placement: \"mounted\",\n variables: { ...config.variables },\n async acquire(context) {\n context.signal?.throwIfAborted();\n const name = `outpost-${randomUUID()}`;\n const image = config.image ?? imageName(context.repository);\n const user = config.user ?? {\n uid: process.getuid?.() ?? containerDefaults.uid,\n gid: process.getgid?.() ?? containerDefaults.gid,\n };\n invariant(\n Number.isInteger(user.uid) &&\n user.uid >= 0 &&\n Number.isInteger(user.gid) &&\n user.gid >= 0,\n \"Invalid container user\",\n );\n const call = (args: readonly string[], extra: Partial<Command> = {}) =>\n requireSuccess(\n {\n executable: engine,\n arguments: args,\n deadlineMs: containerDefaults.deadlineMs,\n ...extra,\n },\n executor,\n );\n await containerPreflight(engine, platform, call, config, image, user);\n const root = containerDefaults.root,\n home = containerDefaults.home;\n const { env, volumes, fileParents } = await containerMounts(\n context,\n config,\n platform,\n root,\n home,\n );\n const args = containerPlan({\n config,\n engine,\n user,\n root,\n name,\n image,\n volumes,\n fileParents,\n });\n let closed = false,\n releasing: Promise<void> | undefined;\n let unregister = () => {};\n const release = (): Promise<void> => {\n closed = true;\n releasing ??= call([\"rm\", \"--force\", name])\n .then(() => {\n unregister();\n })\n .catch((error) => {\n releasing = undefined;\n throw error;\n });\n return releasing;\n };\n try {\n await call(args, {\n ...(context.signal ? { signal: context.signal } : {}),\n });\n await call(\n [\"start\", name],\n context.signal ? { signal: context.signal } : {},\n );\n for (const parent of fileParents)\n await call([\n \"exec\",\n \"--user\",\n \"0:0\",\n name,\n \"sh\",\n \"-c\",\n `mkdir -p ${quote(parent)} && chown ${user.uid}:${user.gid} ${quote(parent)}`,\n ]);\n if (fileParents.size)\n await call([\n \"exec\",\n \"--user\",\n \"0:0\",\n name,\n \"chown\",\n `${user.uid}:${user.gid}`,\n home,\n ]);\n await call([\n \"exec\",\n name,\n \"sh\",\n \"-c\",\n \"command -v setsid >/dev/null && command -v kill >/dev/null && command -v tar >/dev/null && command -v cp >/dev/null\",\n ]);\n } catch (cause) {\n try {\n await release();\n } catch (cleanup) {\n throw new AggregateError(\n [cause, cleanup],\n \"Sandbox provisioning and cleanup failed\",\n );\n }\n throw cause;\n }\n unregister = registerCleanup(release, () => {\n if (!closed)\n execFileSync(engine, [\"rm\", \"--force\", name], {\n timeout: containerDefaults.cleanupMs,\n stdio: \"ignore\",\n windowsHide: true,\n });\n });\n return {\n root,\n home,\n invoke: containerCommand({\n engine,\n config,\n executor,\n root,\n name,\n env,\n call,\n isClosed: () => closed,\n }),\n ...containerFiles({\n engine,\n config,\n executor,\n root,\n name,\n env,\n call,\n isClosed: () => closed,\n }),\n release,\n };\n },\n };\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"backlog.constants.js","sourceRoot":"","sources":["../../../src/adapters/backlogs/backlog.constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,CAAC;IAC3C,UAAU,EAAE,MAAM;IAClB,WAAW,EAAE,UAAU;CACxB,CAAC,CAAC","sourcesContent":["export const backlogDefaults = Object.freeze({\n deadlineMs: 60_000,\n retainBytes: 16_777_216,\n});\n"]}
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import type { Backlog } from "../../domain/backlog.types.ts";
|
|
2
|
-
import type { Executor } from "../../infrastructure/process.types.ts";
|
|
3
|
-
import type { BacklogSettings } from "./settings.types.ts";
|
|
4
|
-
export declare function beadsBacklog(settings?: BacklogSettings, executor?: Executor): Backlog;
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { invariant } from "../../domain/errors.js";
|
|
2
|
-
import { cli } from "./cli.js";
|
|
3
|
-
import { issue } from "./issue.js";
|
|
4
|
-
export function beadsBacklog(settings = {}, executor) {
|
|
5
|
-
const run = cli("bd", settings, executor);
|
|
6
|
-
const identifier = (id) => {
|
|
7
|
-
invariant(/^[\w][\w.-]*$/.test(id), "Invalid Beads issue id");
|
|
8
|
-
return id;
|
|
9
|
-
};
|
|
10
|
-
return {
|
|
11
|
-
async list(signal) {
|
|
12
|
-
const data = JSON.parse(await run([
|
|
13
|
-
"ready",
|
|
14
|
-
"--json",
|
|
15
|
-
"--limit",
|
|
16
|
-
"0",
|
|
17
|
-
...(settings.label ? ["--label", settings.label] : []),
|
|
18
|
-
], signal));
|
|
19
|
-
invariant(Array.isArray(data), "Invalid Beads backlog");
|
|
20
|
-
return data.map(issue);
|
|
21
|
-
},
|
|
22
|
-
async get(id, signal) {
|
|
23
|
-
const data = JSON.parse(await run(["show", identifier(id), "--json"], signal));
|
|
24
|
-
return issue(Array.isArray(data) ? data[0] : data);
|
|
25
|
-
},
|
|
26
|
-
async close(id, signal) {
|
|
27
|
-
await run(["close", identifier(id)], signal);
|
|
28
|
-
},
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
//# sourceMappingURL=beads-adapter.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"beads-adapter.js","sourceRoot":"","sources":["../../../src/adapters/backlogs/beads-adapter.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAEnD,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAGnC,MAAM,UAAU,YAAY,CAC1B,WAA4B,EAAE,EAC9B,QAAmB;IAEnB,MAAM,GAAG,GAAG,GAAG,CAAC,IAAI,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC1C,MAAM,UAAU,GAAG,CAAC,EAAU,EAAE,EAAE;QAChC,SAAS,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,wBAAwB,CAAC,CAAC;QAC9D,OAAO,EAAE,CAAC;IACZ,CAAC,CAAC;IACF,OAAO;QACL,KAAK,CAAC,IAAI,CAAC,MAAM;YACf,MAAM,IAAI,GAAY,IAAI,CAAC,KAAK,CAC9B,MAAM,GAAG,CACP;gBACE,OAAO;gBACP,QAAQ;gBACR,SAAS;gBACT,GAAG;gBACH,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;aACvD,EACD,MAAM,CACP,CACF,CAAC;YACF,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,uBAAuB,CAAC,CAAC;YACxD,OAAO,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACzB,CAAC;QACD,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,MAAM;YAClB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CACrB,MAAM,GAAG,CAAC,CAAC,MAAM,EAAE,UAAU,CAAC,EAAE,CAAC,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,CACtD,CAAC;YACF,OAAO,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACrD,CAAC;QACD,KAAK,CAAC,KAAK,CAAC,EAAE,EAAE,MAAM;YACpB,MAAM,GAAG,CAAC,CAAC,OAAO,EAAE,UAAU,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;QAC/C,CAAC;KACF,CAAC;AACJ,CAAC","sourcesContent":["import type { Backlog } from \"../../domain/backlog.types.ts\";\nimport { invariant } from \"../../domain/errors.ts\";\nimport type { Executor } from \"../../infrastructure/process.types.ts\";\nimport { cli } from \"./cli.ts\";\nimport { issue } from \"./issue.ts\";\nimport type { BacklogSettings } from \"./settings.types.ts\";\n\nexport function beadsBacklog(\n settings: BacklogSettings = {},\n executor?: Executor,\n): Backlog {\n const run = cli(\"bd\", settings, executor);\n const identifier = (id: string) => {\n invariant(/^[\\w][\\w.-]*$/.test(id), \"Invalid Beads issue id\");\n return id;\n };\n return {\n async list(signal) {\n const data: unknown = JSON.parse(\n await run(\n [\n \"ready\",\n \"--json\",\n \"--limit\",\n \"0\",\n ...(settings.label ? [\"--label\", settings.label] : []),\n ],\n signal,\n ),\n );\n invariant(Array.isArray(data), \"Invalid Beads backlog\");\n return data.map(issue);\n },\n async get(id, signal) {\n const data = JSON.parse(\n await run([\"show\", identifier(id), \"--json\"], signal),\n );\n return issue(Array.isArray(data) ? data[0] : data);\n },\n async close(id, signal) {\n await run([\"close\", identifier(id)], signal);\n },\n };\n}\n"]}
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import type { Executor } from "../../infrastructure/process.types.ts";
|
|
2
|
-
import type { BacklogSettings } from "./settings.types.ts";
|
|
3
|
-
export declare function cli(program: string, settings: BacklogSettings, executor?: Executor): (args: readonly string[], signal?: AbortSignal) => Promise<string>;
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { requireSuccess } from "../../infrastructure/process.js";
|
|
2
|
-
import { resolveVariables } from "../../infrastructure/settings.js";
|
|
3
|
-
import { backlogDefaults } from "./backlog.constants.js";
|
|
4
|
-
export function cli(program, settings, executor) {
|
|
5
|
-
const directory = settings.directory ?? process.cwd();
|
|
6
|
-
return async (args, signal) => {
|
|
7
|
-
signal?.throwIfAborted();
|
|
8
|
-
const variables = await resolveVariables(directory);
|
|
9
|
-
return (await requireSuccess({
|
|
10
|
-
executable: program,
|
|
11
|
-
arguments: args,
|
|
12
|
-
directory,
|
|
13
|
-
variables,
|
|
14
|
-
deadlineMs: settings.deadlineMs ?? backlogDefaults.deadlineMs,
|
|
15
|
-
retain: backlogDefaults.retainBytes,
|
|
16
|
-
...(signal ? { signal } : {}),
|
|
17
|
-
}, executor)).stdout;
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
//# sourceMappingURL=cli.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../../src/adapters/backlogs/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAEjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGzD,MAAM,UAAU,GAAG,CACjB,OAAe,EACf,QAAyB,EACzB,QAAmB;IAEnB,MAAM,SAAS,GAAG,QAAQ,CAAC,SAAS,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IACtD,OAAO,KAAK,EAAE,IAAuB,EAAE,MAAoB,EAAE,EAAE;QAC7D,MAAM,EAAE,cAAc,EAAE,CAAC;QACzB,MAAM,SAAS,GAAG,MAAM,gBAAgB,CAAC,SAAS,CAAC,CAAC;QACpD,OAAO,CACL,MAAM,cAAc,CAClB;YACE,UAAU,EAAE,OAAO;YACnB,SAAS,EAAE,IAAI;YACf,SAAS;YACT,SAAS;YACT,UAAU,EAAE,QAAQ,CAAC,UAAU,IAAI,eAAe,CAAC,UAAU;YAC7D,MAAM,EAAE,eAAe,CAAC,WAAW;YACnC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC9B,EACD,QAAQ,CACT,CACF,CAAC,MAAM,CAAC;IACX,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import { requireSuccess } from \"../../infrastructure/process.ts\";\nimport type { Executor } from \"../../infrastructure/process.types.ts\";\nimport { resolveVariables } from \"../../infrastructure/settings.ts\";\nimport { backlogDefaults } from \"./backlog.constants.ts\";\nimport type { BacklogSettings } from \"./settings.types.ts\";\n\nexport function cli(\n program: string,\n settings: BacklogSettings,\n executor?: Executor,\n) {\n const directory = settings.directory ?? process.cwd();\n return async (args: readonly string[], signal?: AbortSignal) => {\n signal?.throwIfAborted();\n const variables = await resolveVariables(directory);\n return (\n await requireSuccess(\n {\n executable: program,\n arguments: args,\n directory,\n variables,\n deadlineMs: settings.deadlineMs ?? backlogDefaults.deadlineMs,\n retain: backlogDefaults.retainBytes,\n ...(signal ? { signal } : {}),\n },\n executor,\n )\n ).stdout;\n };\n}\n"]}
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import type { Backlog } from "../../domain/backlog.types.ts";
|
|
2
|
-
import type { Executor } from "../../infrastructure/process.types.ts";
|
|
3
|
-
import type { BacklogSettings } from "./settings.types.ts";
|
|
4
|
-
export declare function githubBacklog(settings?: BacklogSettings, executor?: Executor): Backlog;
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { invariant } from "../../domain/errors.js";
|
|
2
|
-
import { cli } from "./cli.js";
|
|
3
|
-
import { issue } from "./issue.js";
|
|
4
|
-
export function githubBacklog(settings = {}, executor) {
|
|
5
|
-
const run = cli("gh", settings, executor);
|
|
6
|
-
const identifier = (id) => {
|
|
7
|
-
invariant(/^[1-9]\d*$/.test(id), "GitHub issue id must be a positive number");
|
|
8
|
-
return id;
|
|
9
|
-
};
|
|
10
|
-
return {
|
|
11
|
-
async list(signal) {
|
|
12
|
-
const endpoint = `repos/{owner}/{repo}/issues?state=open&per_page=100${settings.label ? `&labels=${encodeURIComponent(settings.label)}` : ""}`;
|
|
13
|
-
const pages = JSON.parse(await run(["api", endpoint, "--paginate", "--slurp"], signal));
|
|
14
|
-
invariant(Array.isArray(pages) && pages.every(Array.isArray), "Invalid GitHub issue pages");
|
|
15
|
-
return pages
|
|
16
|
-
.flat()
|
|
17
|
-
.filter((item) => !item.pull_request)
|
|
18
|
-
.map(issue);
|
|
19
|
-
},
|
|
20
|
-
async get(id, signal) {
|
|
21
|
-
return issue(JSON.parse(await run(["issue", "view", identifier(id), "--json", "number,title,body"], signal)));
|
|
22
|
-
},
|
|
23
|
-
async close(id, signal) {
|
|
24
|
-
await run(["issue", "close", identifier(id), "--reason", "completed"], signal);
|
|
25
|
-
},
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
//# sourceMappingURL=github-adapter.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"github-adapter.js","sourceRoot":"","sources":["../../../src/adapters/backlogs/github-adapter.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAEnD,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAGnC,MAAM,UAAU,aAAa,CAC3B,WAA4B,EAAE,EAC9B,QAAmB;IAEnB,MAAM,GAAG,GAAG,GAAG,CAAC,IAAI,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC1C,MAAM,UAAU,GAAG,CAAC,EAAU,EAAE,EAAE;QAChC,SAAS,CACP,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,EACrB,2CAA2C,CAC5C,CAAC;QACF,OAAO,EAAE,CAAC;IACZ,CAAC,CAAC;IACF,OAAO;QACL,KAAK,CAAC,IAAI,CAAC,MAAM;YACf,MAAM,QAAQ,GAAG,sDAAsD,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,WAAW,kBAAkB,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;YAC/I,MAAM,KAAK,GAAY,IAAI,CAAC,KAAK,CAC/B,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,SAAS,CAAC,EAAE,MAAM,CAAC,CAC9D,CAAC;YACF,SAAS,CACP,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,EAClD,4BAA4B,CAC7B,CAAC;YACF,OAAO,KAAK;iBACT,IAAI,EAAE;iBACN,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC;iBACpC,GAAG,CAAC,KAAK,CAAC,CAAC;QAChB,CAAC;QACD,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,MAAM;YAClB,OAAO,KAAK,CACV,IAAI,CAAC,KAAK,CACR,MAAM,GAAG,CACP,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,CAAC,EAAE,QAAQ,EAAE,mBAAmB,CAAC,EAChE,MAAM,CACP,CACF,CACF,CAAC;QACJ,CAAC;QACD,KAAK,CAAC,KAAK,CAAC,EAAE,EAAE,MAAM;YACpB,MAAM,GAAG,CACP,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,CAAC,EAAE,CAAC,EAAE,UAAU,EAAE,WAAW,CAAC,EAC3D,MAAM,CACP,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC","sourcesContent":["import type { Backlog } from \"../../domain/backlog.types.ts\";\nimport { invariant } from \"../../domain/errors.ts\";\nimport type { Executor } from \"../../infrastructure/process.types.ts\";\nimport { cli } from \"./cli.ts\";\nimport { issue } from \"./issue.ts\";\nimport type { BacklogSettings } from \"./settings.types.ts\";\n\nexport function githubBacklog(\n settings: BacklogSettings = {},\n executor?: Executor,\n): Backlog {\n const run = cli(\"gh\", settings, executor);\n const identifier = (id: string) => {\n invariant(\n /^[1-9]\\d*$/.test(id),\n \"GitHub issue id must be a positive number\",\n );\n return id;\n };\n return {\n async list(signal) {\n const endpoint = `repos/{owner}/{repo}/issues?state=open&per_page=100${settings.label ? `&labels=${encodeURIComponent(settings.label)}` : \"\"}`;\n const pages: unknown = JSON.parse(\n await run([\"api\", endpoint, \"--paginate\", \"--slurp\"], signal),\n );\n invariant(\n Array.isArray(pages) && pages.every(Array.isArray),\n \"Invalid GitHub issue pages\",\n );\n return pages\n .flat()\n .filter((item) => !item.pull_request)\n .map(issue);\n },\n async get(id, signal) {\n return issue(\n JSON.parse(\n await run(\n [\"issue\", \"view\", identifier(id), \"--json\", \"number,title,body\"],\n signal,\n ),\n ),\n );\n },\n async close(id, signal) {\n await run(\n [\"issue\", \"close\", identifier(id), \"--reason\", \"completed\"],\n signal,\n );\n },\n };\n}\n"]}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { invariant } from "../../domain/errors.js";
|
|
2
|
-
export function issue(input) {
|
|
3
|
-
invariant(!!input && typeof input === "object", "Tracker returned an invalid issue");
|
|
4
|
-
const item = input;
|
|
5
|
-
invariant((typeof item.id === "string" || typeof item.number === "number") &&
|
|
6
|
-
typeof item.title === "string", "Tracker issue needs an id and a title");
|
|
7
|
-
return {
|
|
8
|
-
id: String(item.number ?? item.id),
|
|
9
|
-
title: item.title,
|
|
10
|
-
body: String(item.body ?? item.description ?? ""),
|
|
11
|
-
};
|
|
12
|
-
}
|
|
13
|
-
//# sourceMappingURL=issue.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"issue.js","sourceRoot":"","sources":["../../../src/adapters/backlogs/issue.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAEnD,MAAM,UAAU,KAAK,CAAC,KAAc;IAClC,SAAS,CACP,CAAC,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EACpC,mCAAmC,CACpC,CAAC;IACF,MAAM,IAAI,GAAG,KAAgC,CAAC;IAC9C,SAAS,CACP,CAAC,OAAO,IAAI,CAAC,EAAE,KAAK,QAAQ,IAAI,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ,CAAC;QAC9D,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ,EAChC,uCAAuC,CACxC,CAAC;IACF,OAAO;QACL,EAAE,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,EAAE,CAAC;QAClC,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,WAAW,IAAI,EAAE,CAAC;KAClD,CAAC;AACJ,CAAC","sourcesContent":["import type { Issue } from \"../../domain/backlog.types.ts\";\nimport { invariant } from \"../../domain/errors.ts\";\n\nexport function issue(input: unknown): Issue {\n invariant(\n !!input && typeof input === \"object\",\n \"Tracker returned an invalid issue\",\n );\n const item = input as Record<string, unknown>;\n invariant(\n (typeof item.id === \"string\" || typeof item.number === \"number\") &&\n typeof item.title === \"string\",\n \"Tracker issue needs an id and a title\",\n );\n return {\n id: String(item.number ?? item.id),\n title: item.title,\n body: String(item.body ?? item.description ?? \"\"),\n };\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"settings.types.js","sourceRoot":"","sources":["../../../src/adapters/backlogs/settings.types.ts"],"names":[],"mappings":"","sourcesContent":["export interface BacklogSettings {\n readonly directory?: string;\n readonly label?: string;\n readonly deadlineMs?: number;\n}\n"]}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { invariant, OutpostError } from "../domain/errors.js";
|
|
2
|
-
import { createSandbox } from "./sandbox.js";
|
|
3
|
-
export async function integrateIssues(context, completed) {
|
|
4
|
-
const { runtime, standards, options: { merger }, } = context;
|
|
5
|
-
const integration = await createSandbox({
|
|
6
|
-
...runtime,
|
|
7
|
-
agent: merger ?? runtime.agent,
|
|
8
|
-
branch: { mode: "integrate" },
|
|
9
|
-
});
|
|
10
|
-
let integrated = false;
|
|
11
|
-
try {
|
|
12
|
-
for (const item of completed) {
|
|
13
|
-
const merged = await integration.command({
|
|
14
|
-
executable: "git",
|
|
15
|
-
arguments: ["merge", "--no-edit", item.head],
|
|
16
|
-
...(runtime.signal ? { signal: runtime.signal } : {}),
|
|
17
|
-
});
|
|
18
|
-
await integration.dispatch({
|
|
19
|
-
agent: merger ?? runtime.agent,
|
|
20
|
-
...(runtime.signal ? { signal: runtime.signal } : {}),
|
|
21
|
-
brief: {
|
|
22
|
-
text: `Validate integration of issue ${item.id} from commit ${item.head}. ${merged.status ? "Resolve the current Git merge conflict and finish the merge." : "The commits have been merged."} Run relevant tests, fix integration defects and commit any changes. ${standards} Do not close issues. When complete, write <outpost>done</outpost>.`,
|
|
23
|
-
},
|
|
24
|
-
});
|
|
25
|
-
const verified = await integration.command({
|
|
26
|
-
executable: "git",
|
|
27
|
-
arguments: ["merge-base", "--is-ancestor", item.head, "HEAD"],
|
|
28
|
-
});
|
|
29
|
-
if (verified.status)
|
|
30
|
-
throw new OutpostError("conflict", "Merge did not include the issue commits", { issue: item.id, branch: item.branch });
|
|
31
|
-
}
|
|
32
|
-
const clean = await integration.command({
|
|
33
|
-
executable: "git",
|
|
34
|
-
arguments: ["status", "--porcelain"],
|
|
35
|
-
});
|
|
36
|
-
invariant(clean.status === 0 && !clean.stdout.trim(), "Integration has uncommitted changes");
|
|
37
|
-
await integration.workspace.integrate();
|
|
38
|
-
integrated = true;
|
|
39
|
-
}
|
|
40
|
-
finally {
|
|
41
|
-
await integration.close({ preserve: !integrated });
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
//# sourceMappingURL=campaign-integration.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"campaign-integration.js","sourceRoot":"","sources":["../../src/application/campaign-integration.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAE9D,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,OAAwB,EACxB,SAAoC;IAEpC,MAAM,EACJ,OAAO,EACP,SAAS,EACT,OAAO,EAAE,EAAE,MAAM,EAAE,GACpB,GAAG,OAAO,CAAC;IACZ,MAAM,WAAW,GAAG,MAAM,aAAa,CAAC;QACtC,GAAG,OAAO;QACV,KAAK,EAAE,MAAM,IAAI,OAAO,CAAC,KAAK;QAC9B,MAAM,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE;KAC9B,CAAC,CAAC;IACH,IAAI,UAAU,GAAG,KAAK,CAAC;IACvB,IAAI,CAAC;QACH,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;YAC7B,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,OAAO,CAAC;gBACvC,UAAU,EAAE,KAAK;gBACjB,SAAS,EAAE,CAAC,OAAO,EAAE,WAAW,EAAE,IAAI,CAAC,IAAI,CAAC;gBAC5C,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACtD,CAAC,CAAC;YACH,MAAM,WAAW,CAAC,QAAQ,CAAC;gBACzB,KAAK,EAAE,MAAM,IAAI,OAAO,CAAC,KAAK;gBAC9B,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACrD,KAAK,EAAE;oBACL,IAAI,EAAE,iCAAiC,IAAI,CAAC,EAAE,gBAAgB,IAAI,CAAC,IAAI,KAAK,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,8DAA8D,CAAC,CAAC,CAAC,+BAA+B,wEAAwE,SAAS,qEAAqE;iBACnV;aACF,CAAC,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,OAAO,CAAC;gBACzC,UAAU,EAAE,KAAK;gBACjB,SAAS,EAAE,CAAC,YAAY,EAAE,eAAe,EAAE,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC;aAC9D,CAAC,CAAC;YACH,IAAI,QAAQ,CAAC,MAAM;gBACjB,MAAM,IAAI,YAAY,CACpB,UAAU,EACV,yCAAyC,EACzC,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CACxC,CAAC;QACN,CAAC;QACD,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,OAAO,CAAC;YACtC,UAAU,EAAE,KAAK;YACjB,SAAS,EAAE,CAAC,QAAQ,EAAE,aAAa,CAAC;SACrC,CAAC,CAAC;QACH,SAAS,CACP,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,EAC1C,qCAAqC,CACtC,CAAC;QACF,MAAM,WAAW,CAAC,SAAS,CAAC,SAAS,EAAE,CAAC;QACxC,UAAU,GAAG,IAAI,CAAC;IACpB,CAAC;YAAS,CAAC;QACT,MAAM,WAAW,CAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC,UAAU,EAAE,CAAC,CAAC;IACrD,CAAC;AACH,CAAC","sourcesContent":["import { invariant, OutpostError } from \"../domain/errors.ts\";\nimport type { CampaignContext, CompletedIssue } from \"./campaign.types.ts\";\nimport { createSandbox } from \"./sandbox.ts\";\n\nexport async function integrateIssues(\n context: CampaignContext,\n completed: readonly CompletedIssue[],\n): Promise<void> {\n const {\n runtime,\n standards,\n options: { merger },\n } = context;\n const integration = await createSandbox({\n ...runtime,\n agent: merger ?? runtime.agent,\n branch: { mode: \"integrate\" },\n });\n let integrated = false;\n try {\n for (const item of completed) {\n const merged = await integration.command({\n executable: \"git\",\n arguments: [\"merge\", \"--no-edit\", item.head],\n ...(runtime.signal ? { signal: runtime.signal } : {}),\n });\n await integration.dispatch({\n agent: merger ?? runtime.agent,\n ...(runtime.signal ? { signal: runtime.signal } : {}),\n brief: {\n text: `Validate integration of issue ${item.id} from commit ${item.head}. ${merged.status ? \"Resolve the current Git merge conflict and finish the merge.\" : \"The commits have been merged.\"} Run relevant tests, fix integration defects and commit any changes. ${standards} Do not close issues. When complete, write <outpost>done</outpost>.`,\n },\n });\n const verified = await integration.command({\n executable: \"git\",\n arguments: [\"merge-base\", \"--is-ancestor\", item.head, \"HEAD\"],\n });\n if (verified.status)\n throw new OutpostError(\n \"conflict\",\n \"Merge did not include the issue commits\",\n { issue: item.id, branch: item.branch },\n );\n }\n const clean = await integration.command({\n executable: \"git\",\n arguments: [\"status\", \"--porcelain\"],\n });\n invariant(\n clean.status === 0 && !clean.stdout.trim(),\n \"Integration has uncommitted changes\",\n );\n await integration.workspace.integrate();\n integrated = true;\n } finally {\n await integration.close({ preserve: !integrated });\n }\n}\n"]}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { randomUUID } from "node:crypto";
|
|
2
|
-
import { readPlan } from "../domain/backlog.js";
|
|
3
|
-
import { invariant } from "../domain/errors.js";
|
|
4
|
-
import { response } from "../domain/response.js";
|
|
5
|
-
import { dispatch } from "./dispatch.js";
|
|
6
|
-
export async function planIssues(context, ready, concurrency) {
|
|
7
|
-
const { runtime, emit, options: { planner }, } = context;
|
|
8
|
-
const prefix = `outpost/batch-${randomUUID().slice(0, 8)}`;
|
|
9
|
-
let assignments;
|
|
10
|
-
if (planner !== false) {
|
|
11
|
-
emit("plan");
|
|
12
|
-
const plan = await dispatch({
|
|
13
|
-
...runtime,
|
|
14
|
-
agent: planner ?? runtime.agent,
|
|
15
|
-
branch: { mode: "named", name: `${prefix}-planning` },
|
|
16
|
-
brief: {
|
|
17
|
-
text: `Select independent, unblocked issues from this backlog. Read the repository without editing files. Return <assignments>{"issues":[{"id":"an existing id","branch":"${prefix}-short-name"}]}</assignments>. Return an empty array when blocked.\n${JSON.stringify(ready)}`,
|
|
18
|
-
},
|
|
19
|
-
response: response.json({
|
|
20
|
-
tag: "assignments",
|
|
21
|
-
schema: readPlan,
|
|
22
|
-
repairs: 1,
|
|
23
|
-
}),
|
|
24
|
-
});
|
|
25
|
-
invariant(!plan.commits.length && !plan.retainedDirectory, "Planner changed its workspace; inspect the planning branch before continuing");
|
|
26
|
-
assignments = plan.value;
|
|
27
|
-
}
|
|
28
|
-
else
|
|
29
|
-
assignments = ready.slice(0, concurrency).map((issue, index) => ({
|
|
30
|
-
id: issue.id,
|
|
31
|
-
branch: `${prefix}-${index + 1}`,
|
|
32
|
-
}));
|
|
33
|
-
return assignments;
|
|
34
|
-
}
|
|
35
|
-
//# sourceMappingURL=campaign-planner.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"campaign-planner.js","sourceRoot":"","sources":["../../src/application/campaign-planner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAEhD,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEjD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,OAAwB,EACxB,KAAuB,EACvB,WAAmB;IAEnB,MAAM,EACJ,OAAO,EACP,IAAI,EACJ,OAAO,EAAE,EAAE,OAAO,EAAE,GACrB,GAAG,OAAO,CAAC;IACZ,MAAM,MAAM,GAAG,iBAAiB,UAAU,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;IAC3D,IAAI,WAAkC,CAAC;IACvC,IAAI,OAAO,KAAK,KAAK,EAAE,CAAC;QACtB,IAAI,CAAC,MAAM,CAAC,CAAC;QACb,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC;YAC1B,GAAG,OAAO;YACV,KAAK,EAAE,OAAO,IAAI,OAAO,CAAC,KAAK;YAC/B,MAAM,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,MAAM,WAAW,EAAE;YACrD,KAAK,EAAE;gBACL,IAAI,EAAE,sKAAsK,MAAM,uEAAuE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE;aACjR;YACD,QAAQ,EAAE,QAAQ,CAAC,IAAI,CAAC;gBACtB,GAAG,EAAE,aAAa;gBAClB,MAAM,EAAE,QAAQ;gBAChB,OAAO,EAAE,CAAC;aACX,CAAC;SACH,CAAC,CAAC;QACH,SAAS,CACP,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAC/C,8EAA8E,CAC/E,CAAC;QACF,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC;IAC3B,CAAC;;QACC,WAAW,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;YAC/D,EAAE,EAAE,KAAK,CAAC,EAAE;YACZ,MAAM,EAAE,GAAG,MAAM,IAAI,KAAK,GAAG,CAAC,EAAE;SACjC,CAAC,CAAC,CAAC;IAEN,OAAO,WAAW,CAAC;AACrB,CAAC","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { readPlan } from \"../domain/backlog.ts\";\nimport type { Assignment, Issue } from \"../domain/backlog.types.ts\";\nimport { invariant } from \"../domain/errors.ts\";\nimport { response } from \"../domain/response.ts\";\nimport type { CampaignContext } from \"./campaign.types.ts\";\nimport { dispatch } from \"./dispatch.ts\";\n\nexport async function planIssues(\n context: CampaignContext,\n ready: readonly Issue[],\n concurrency: number,\n): Promise<readonly Assignment[]> {\n const {\n runtime,\n emit,\n options: { planner },\n } = context;\n const prefix = `outpost/batch-${randomUUID().slice(0, 8)}`;\n let assignments: readonly Assignment[];\n if (planner !== false) {\n emit(\"plan\");\n const plan = await dispatch({\n ...runtime,\n agent: planner ?? runtime.agent,\n branch: { mode: \"named\", name: `${prefix}-planning` },\n brief: {\n text: `Select independent, unblocked issues from this backlog. Read the repository without editing files. Return <assignments>{\"issues\":[{\"id\":\"an existing id\",\"branch\":\"${prefix}-short-name\"}]}</assignments>. Return an empty array when blocked.\\n${JSON.stringify(ready)}`,\n },\n response: response.json({\n tag: \"assignments\",\n schema: readPlan,\n repairs: 1,\n }),\n });\n invariant(\n !plan.commits.length && !plan.retainedDirectory,\n \"Planner changed its workspace; inspect the planning branch before continuing\",\n );\n assignments = plan.value;\n } else\n assignments = ready.slice(0, concurrency).map((issue, index) => ({\n id: issue.id,\n branch: `${prefix}-${index + 1}`,\n }));\n\n return assignments;\n}\n"]}
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import type { Assignment } from "../domain/backlog.types.ts";
|
|
2
|
-
import type { CampaignContext, CompletedIssue } from "./campaign.types.ts";
|
|
3
|
-
export declare function implementIssue(context: CampaignContext, assignment: Assignment, baseline: string, signal: AbortSignal): Promise<CompletedIssue | undefined>;
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { invariant } from "../domain/errors.js";
|
|
2
|
-
import { git } from "../infrastructure/git/command.js";
|
|
3
|
-
import { campaignDefaults } from "./campaign.constants.js";
|
|
4
|
-
import { createSandbox } from "./sandbox.js";
|
|
5
|
-
export async function implementIssue(context, assignment, baseline, signal) {
|
|
6
|
-
const { runtime, standards, emit, options: { backlog, reviewer, implementationPasses, reviewPasses }, } = context;
|
|
7
|
-
const issue = await backlog.get(assignment.id, signal);
|
|
8
|
-
invariant(issue.id === assignment.id, "Tracker returned a different issue");
|
|
9
|
-
const sandbox = await createSandbox({
|
|
10
|
-
...runtime,
|
|
11
|
-
signal,
|
|
12
|
-
branch: { mode: "named", name: assignment.branch, from: baseline },
|
|
13
|
-
});
|
|
14
|
-
let success = false;
|
|
15
|
-
try {
|
|
16
|
-
emit("implement", issue.id);
|
|
17
|
-
const implemented = await sandbox.dispatch({
|
|
18
|
-
agent: runtime.agent,
|
|
19
|
-
signal,
|
|
20
|
-
passes: implementationPasses ?? campaignDefaults.implementationPasses,
|
|
21
|
-
brief: {
|
|
22
|
-
text: `Implement issue ${issue.id}: ${issue.title}\n${issue.body ?? ""}\n${standards}\nDo not close the issue. When complete, write <outpost>done</outpost>.`,
|
|
23
|
-
},
|
|
24
|
-
});
|
|
25
|
-
if (!implemented.commits.length) {
|
|
26
|
-
success = true;
|
|
27
|
-
return undefined;
|
|
28
|
-
}
|
|
29
|
-
if (reviewer !== false) {
|
|
30
|
-
emit("review", issue.id);
|
|
31
|
-
await sandbox.dispatch({
|
|
32
|
-
agent: reviewer ?? runtime.agent,
|
|
33
|
-
signal,
|
|
34
|
-
passes: reviewPasses ?? campaignDefaults.reviewPasses,
|
|
35
|
-
brief: {
|
|
36
|
-
text: `Review issue ${issue.id} on ${assignment.branch}. Inspect git diff ${baseline}...HEAD, fix concrete defects, run the relevant tests and commit corrections.\n${standards}\nDo not close the issue. When complete, write <outpost>done</outpost>.`,
|
|
37
|
-
},
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
const clean = await sandbox.command({
|
|
41
|
-
executable: "git",
|
|
42
|
-
arguments: ["status", "--porcelain"],
|
|
43
|
-
signal,
|
|
44
|
-
});
|
|
45
|
-
invariant(clean.status === 0 && !clean.stdout.trim(), `Issue ${issue.id} has uncommitted changes`);
|
|
46
|
-
const head = (await git(sandbox.workspace.directory, ["rev-parse", "HEAD"])).trim();
|
|
47
|
-
success = true;
|
|
48
|
-
return { ...assignment, head };
|
|
49
|
-
}
|
|
50
|
-
finally {
|
|
51
|
-
await sandbox.close({ preserve: !success });
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
//# sourceMappingURL=campaign-worker.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"campaign-worker.js","sourceRoot":"","sources":["../../src/application/campaign-worker.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Assignment, Issue } from \"../domain/backlog.types.ts\";\nimport { invariant } from \"../domain/errors.ts\";\nimport { git } from \"../infrastructure/git/command.ts\";\nimport { campaignDefaults } from \"./campaign.constants.ts\";\nimport type { CampaignContext, CompletedIssue } from \"./campaign.types.ts\";\nimport { createSandbox } from \"./sandbox.ts\";\n\nexport async function implementIssue(\n context: CampaignContext,\n assignment: Assignment,\n baseline: string,\n signal: AbortSignal,\n): Promise<CompletedIssue | undefined> {\n const {\n runtime,\n standards,\n emit,\n options: { backlog, reviewer, implementationPasses, reviewPasses },\n } = context;\n const issue: Issue = await backlog.get(assignment.id, signal);\n invariant(issue.id === assignment.id, \"Tracker returned a different issue\");\n const sandbox = await createSandbox({\n ...runtime,\n signal,\n branch: { mode: \"named\", name: assignment.branch, from: baseline },\n });\n let success = false;\n try {\n emit(\"implement\", issue.id);\n const implemented = await sandbox.dispatch({\n agent: runtime.agent,\n signal,\n passes: implementationPasses ?? campaignDefaults.implementationPasses,\n brief: {\n text: `Implement issue ${issue.id}: ${issue.title}\\n${issue.body ?? \"\"}\\n${standards}\\nDo not close the issue. When complete, write <outpost>done</outpost>.`,\n },\n });\n if (!implemented.commits.length) {\n success = true;\n return undefined;\n }\n if (reviewer !== false) {\n emit(\"review\", issue.id);\n await sandbox.dispatch({\n agent: reviewer ?? runtime.agent,\n signal,\n passes: reviewPasses ?? campaignDefaults.reviewPasses,\n brief: {\n text: `Review issue ${issue.id} on ${assignment.branch}. Inspect git diff ${baseline}...HEAD, fix concrete defects, run the relevant tests and commit corrections.\\n${standards}\\nDo not close the issue. When complete, write <outpost>done</outpost>.`,\n },\n });\n }\n const clean = await sandbox.command({\n executable: \"git\",\n arguments: [\"status\", \"--porcelain\"],\n signal,\n });\n invariant(\n clean.status === 0 && !clean.stdout.trim(),\n `Issue ${issue.id} has uncommitted changes`,\n );\n const head = (\n await git(sandbox.workspace.directory, [\"rev-parse\", \"HEAD\"])\n ).trim();\n success = true;\n return { ...assignment, head };\n } finally {\n await sandbox.close({ preserve: !success });\n }\n}\n"]}
|