@kitman-sh/cli 0.0.0-stage → 0.6.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/dist/chunk-3j7sewn0.js +4618 -0
- package/dist/chunk-6h8ghah0.js +14 -0
- package/dist/chunk-brp7cekg.js +13 -0
- package/dist/chunk-dsefng1v.js +1085 -0
- package/dist/chunk-fc0v325q.js +75 -0
- package/dist/chunk-h8ctzn91.js +241 -0
- package/dist/chunk-hrvcz0m4.js +211 -0
- package/dist/chunk-hw7qkap1.js +1517 -0
- package/dist/chunk-n32jhswz.js +964 -0
- package/dist/chunk-tfr74ays.js +7060 -0
- package/dist/chunk-txyq8r41.js +25537 -0
- package/dist/chunk-xdk488qp.js +364 -0
- package/dist/egress-proxy.ts +107 -0
- package/dist/index.js +5738 -0
- package/package.json +16 -4
- package/README.md +0 -3
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import {
|
|
3
|
+
TaggedError,
|
|
4
|
+
tryPromise,
|
|
5
|
+
is,
|
|
6
|
+
encodeEffect,
|
|
7
|
+
optionalKey,
|
|
8
|
+
String2,
|
|
9
|
+
Record,
|
|
10
|
+
ArraySchema,
|
|
11
|
+
Union,
|
|
12
|
+
TaggedStruct,
|
|
13
|
+
fromJsonString,
|
|
14
|
+
TaggedError2,
|
|
15
|
+
toCodecJson,
|
|
16
|
+
Json,
|
|
17
|
+
guard,
|
|
18
|
+
ProgramWorkUnit
|
|
19
|
+
} from "./chunk-txyq8r41.js";
|
|
20
|
+
import {
|
|
21
|
+
LoopManifest
|
|
22
|
+
} from "./chunk-hrvcz0m4.js";
|
|
23
|
+
import {
|
|
24
|
+
ManifestInvalid,
|
|
25
|
+
make,
|
|
26
|
+
Suspended,
|
|
27
|
+
LoopCheckError
|
|
28
|
+
} from "./chunk-n32jhswz.js";
|
|
29
|
+
import {
|
|
30
|
+
RunnerRpcError
|
|
31
|
+
} from "./chunk-xdk488qp.js";
|
|
32
|
+
|
|
33
|
+
// packages/sdk/src/program/engine.ts
|
|
34
|
+
class JournalWriteFailed extends TaggedError("JournalWriteFailed") {
|
|
35
|
+
get message() {
|
|
36
|
+
return `Journal write failed: ${this.cause.message}`;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
var JournalEntries = Record(String2, Json);
|
|
40
|
+
var isSuspended = is(Suspended);
|
|
41
|
+
var emptyWorkflow = make("kitman-loop/none", { payload: {}, idempotencyKey: () => "none" });
|
|
42
|
+
var replayStatuses = new Set([401, 403, 409, 429]);
|
|
43
|
+
var isRunnerRpcError = is(RunnerRpcError);
|
|
44
|
+
var programLease = (work) => ({
|
|
45
|
+
workUnitId: work.id,
|
|
46
|
+
leaseOwnerId: work.lease.leaseOwnerId,
|
|
47
|
+
runnerReplicaId: work.lease.runnerReplicaId,
|
|
48
|
+
leaseId: work.lease.leaseId,
|
|
49
|
+
attempt: work.lease.attempt,
|
|
50
|
+
fencingToken: work.lease.fencingToken,
|
|
51
|
+
capacitySlot: work.lease.capacitySlot
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// packages/sdk/src/program/host.ts
|
|
55
|
+
var describeFlag = "--kitman-describe";
|
|
56
|
+
var Described = Union([
|
|
57
|
+
TaggedStruct("Described", {
|
|
58
|
+
loops: ArraySchema(LoopManifest),
|
|
59
|
+
agents: Record(String2, Json),
|
|
60
|
+
schedules: optionalKey(Record(String2, Json)),
|
|
61
|
+
kits: optionalKey(Record(String2, Json))
|
|
62
|
+
}),
|
|
63
|
+
TaggedStruct("Refused", { error: Union([ManifestInvalid, LoopCheckError]) })
|
|
64
|
+
]);
|
|
65
|
+
var encodeDescribed = encodeEffect(fromJsonString(toCodecJson(Described)));
|
|
66
|
+
|
|
67
|
+
class ProgramRefused extends TaggedError2()("ProgramRefused", { reason: String2 }) {
|
|
68
|
+
get message() {
|
|
69
|
+
return this.reason;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
var readStdin = tryPromise(() => Bun.stdin.text());
|
|
73
|
+
var isWorkUnit = guard(ProgramWorkUnit);
|
|
74
|
+
|
|
75
|
+
export { programLease, describeFlag, Described };
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import {
|
|
3
|
+
isString,
|
|
4
|
+
isTagged,
|
|
5
|
+
all,
|
|
6
|
+
forEach,
|
|
7
|
+
succeed5,
|
|
8
|
+
gen,
|
|
9
|
+
fail4,
|
|
10
|
+
try_,
|
|
11
|
+
flatMap,
|
|
12
|
+
map3,
|
|
13
|
+
catchTags,
|
|
14
|
+
mapError,
|
|
15
|
+
ignore,
|
|
16
|
+
orElseSucceed,
|
|
17
|
+
scoped,
|
|
18
|
+
acquireRelease,
|
|
19
|
+
decodeText,
|
|
20
|
+
mkString,
|
|
21
|
+
FileSystem,
|
|
22
|
+
Path,
|
|
23
|
+
ChildProcessSpawner,
|
|
24
|
+
make15,
|
|
25
|
+
decodeUnknownEffect,
|
|
26
|
+
decodeEffect,
|
|
27
|
+
optionalKey,
|
|
28
|
+
Literal,
|
|
29
|
+
String2,
|
|
30
|
+
Struct,
|
|
31
|
+
Record,
|
|
32
|
+
ArraySchema,
|
|
33
|
+
Union,
|
|
34
|
+
Literals,
|
|
35
|
+
fromJsonString,
|
|
36
|
+
TaggedError2,
|
|
37
|
+
toCodecJson,
|
|
38
|
+
digestSha256
|
|
39
|
+
} from "./chunk-txyq8r41.js";
|
|
40
|
+
import {
|
|
41
|
+
AgentDeclaration,
|
|
42
|
+
KitInstallationDeclaration,
|
|
43
|
+
KitAssignmentDeclaration,
|
|
44
|
+
PackageDeclarations
|
|
45
|
+
} from "./chunk-hrvcz0m4.js";
|
|
46
|
+
import"./chunk-hw7qkap1.js";
|
|
47
|
+
import {
|
|
48
|
+
RunnerRpcProtocolVersion
|
|
49
|
+
} from "./chunk-xdk488qp.js";
|
|
50
|
+
import"./chunk-n32jhswz.js";
|
|
51
|
+
import {
|
|
52
|
+
describeFlag,
|
|
53
|
+
Described
|
|
54
|
+
} from "./chunk-fc0v325q.js";
|
|
55
|
+
|
|
56
|
+
// packages/sdk/src/build/index.ts
|
|
57
|
+
class DependencyInstallFailed extends TaggedError2()("DependencyInstallFailed", {
|
|
58
|
+
reason: String2
|
|
59
|
+
}) {
|
|
60
|
+
get message() {
|
|
61
|
+
return `Dependencies do not install from the lockfile: ${this.reason}`;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
class BundleFailed extends TaggedError2()("BundleFailed", { reason: String2 }) {
|
|
66
|
+
get message() {
|
|
67
|
+
return `The Package does not bundle: ${this.reason}`;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
class DeclarationsInvalid extends TaggedError2()("DeclarationsInvalid", {
|
|
72
|
+
reason: String2
|
|
73
|
+
}) {
|
|
74
|
+
get message() {
|
|
75
|
+
return `The Package's declarations are invalid: ${this.reason}`;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
var RepositoryText = Union([String2, Struct({ file: String2 })]);
|
|
79
|
+
var ConfigAgents = Record(String2, Struct({
|
|
80
|
+
extends: optionalKey(String2),
|
|
81
|
+
instructions: optionalKey(RepositoryText),
|
|
82
|
+
harness: optionalKey(String2),
|
|
83
|
+
model: optionalKey(String2),
|
|
84
|
+
effort: AgentDeclaration.fields.effort,
|
|
85
|
+
kits: optionalKey(ArraySchema(String2)),
|
|
86
|
+
network: optionalKey(Union([Struct({ hosts: ArraySchema(String2) }), Literal("open")])),
|
|
87
|
+
sandbox: optionalKey(Literal("docker"))
|
|
88
|
+
}));
|
|
89
|
+
var ConfigKits = Record(String2, Union([
|
|
90
|
+
KitInstallationDeclaration,
|
|
91
|
+
KitAssignmentDeclaration,
|
|
92
|
+
Struct({
|
|
93
|
+
name: String2,
|
|
94
|
+
kind: optionalKey(Literals(["technology", "brand", "domain", "process", "other"])),
|
|
95
|
+
description: optionalKey(String2),
|
|
96
|
+
context: RepositoryText,
|
|
97
|
+
skills: optionalKey(ArraySchema(String2))
|
|
98
|
+
})
|
|
99
|
+
]));
|
|
100
|
+
var run = (command, args, cwd) => gen(function* () {
|
|
101
|
+
const spawner = yield* ChildProcessSpawner;
|
|
102
|
+
const handle = yield* spawner.spawn(make15(command, args, { cwd, stdin: "ignore" }));
|
|
103
|
+
const [stdout, stderr, exitCode] = yield* all([
|
|
104
|
+
mkString(decodeText(handle.stdout)),
|
|
105
|
+
mkString(decodeText(handle.stderr)),
|
|
106
|
+
handle.exitCode
|
|
107
|
+
], { concurrency: 3 });
|
|
108
|
+
return { stdout, stderr, ok: exitCode === 0 };
|
|
109
|
+
}).pipe(scoped);
|
|
110
|
+
var failure = (result) => (result.stderr.trim() || result.stdout.trim()).slice(-2000);
|
|
111
|
+
var provenance = (directory) => gen(function* () {
|
|
112
|
+
const git = (...args) => run("git", args, directory).pipe(map3((result) => result.ok ? result.stdout.trim() : undefined), orElseSucceed(() => {
|
|
113
|
+
return;
|
|
114
|
+
}));
|
|
115
|
+
const repository = yield* git("remote", "get-url", "origin");
|
|
116
|
+
const commit = yield* git("rev-parse", "HEAD");
|
|
117
|
+
const status = yield* git("status", "--porcelain");
|
|
118
|
+
return {
|
|
119
|
+
...repository ? { repository } : undefined,
|
|
120
|
+
...commit ? { commit } : undefined,
|
|
121
|
+
clean: commit !== undefined && status === ""
|
|
122
|
+
};
|
|
123
|
+
});
|
|
124
|
+
var inRepository = (directory, file, what) => gen(function* () {
|
|
125
|
+
const path = yield* Path;
|
|
126
|
+
const resolved = path.resolve(directory, file);
|
|
127
|
+
if (path.relative(directory, resolved).startsWith(".."))
|
|
128
|
+
return yield* new DeclarationsInvalid({ reason: `${what} ${file} is outside the repository` });
|
|
129
|
+
return resolved;
|
|
130
|
+
});
|
|
131
|
+
var readText = (directory, text, what) => gen(function* () {
|
|
132
|
+
if (isString(text))
|
|
133
|
+
return text;
|
|
134
|
+
const fs = yield* FileSystem;
|
|
135
|
+
const file = yield* inRepository(directory, text.file, what);
|
|
136
|
+
return yield* fs.readFileString(file).pipe(mapError(() => new DeclarationsInvalid({ reason: `${what} ${text.file} does not read` })));
|
|
137
|
+
});
|
|
138
|
+
var readAgents = (directory, agents) => forEach(Object.entries(agents), ([id, { instructions, ...agent }]) => instructions === undefined ? succeed5([id, agent]) : map3(readText(directory, instructions, `Agent "${id}" instructions`), (text) => [id, { ...agent, instructions: text.trim() }])).pipe(map3(Object.fromEntries));
|
|
139
|
+
var utf8 = new TextDecoder("utf-8", { fatal: true });
|
|
140
|
+
var readSkill = (directory, skill, what) => gen(function* () {
|
|
141
|
+
const fs = yield* FileSystem;
|
|
142
|
+
const path = yield* Path;
|
|
143
|
+
const root = yield* inRepository(directory, skill, what);
|
|
144
|
+
const unreadable = () => new DeclarationsInvalid({ reason: `${what} ${skill} does not read` });
|
|
145
|
+
const entries = yield* fs.readDirectory(root, { recursive: true }).pipe(mapError(unreadable));
|
|
146
|
+
const files = {};
|
|
147
|
+
for (const entry of entries.toSorted()) {
|
|
148
|
+
const file = path.join(root, entry);
|
|
149
|
+
if ((yield* fs.stat(file).pipe(mapError(unreadable))).type !== "File")
|
|
150
|
+
continue;
|
|
151
|
+
const bytes = yield* fs.readFile(file).pipe(mapError(unreadable));
|
|
152
|
+
const text = yield* try_({
|
|
153
|
+
try: () => utf8.decode(bytes),
|
|
154
|
+
catch: () => new DeclarationsInvalid({ reason: `${what} ${skill} holds a binary file, ${entry}` })
|
|
155
|
+
});
|
|
156
|
+
if (text.includes("\x00"))
|
|
157
|
+
return yield* new DeclarationsInvalid({ reason: `${what} ${skill} holds a binary file, ${entry}` });
|
|
158
|
+
files[entry.split(path.sep).join("/")] = text;
|
|
159
|
+
}
|
|
160
|
+
if (files["SKILL.md"] === undefined)
|
|
161
|
+
return yield* new DeclarationsInvalid({ reason: `${what} ${skill} has no SKILL.md` });
|
|
162
|
+
return [path.basename(root), files];
|
|
163
|
+
});
|
|
164
|
+
var readKits = (directory, kits) => forEach(Object.entries(kits), ([key, kit]) => gen(function* () {
|
|
165
|
+
if (!("context" in kit))
|
|
166
|
+
return [key, kit];
|
|
167
|
+
const { context, skills, ...authored } = kit;
|
|
168
|
+
const what = `Kit "${key}"`;
|
|
169
|
+
return [
|
|
170
|
+
key,
|
|
171
|
+
{
|
|
172
|
+
...authored,
|
|
173
|
+
context: yield* readText(directory, context, `${what} context`),
|
|
174
|
+
...skills === undefined ? undefined : {
|
|
175
|
+
skills: Object.fromEntries(yield* forEach(skills, (skill) => readSkill(directory, skill, `${what} skill`)))
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
];
|
|
179
|
+
})).pipe(map3(Object.fromEntries));
|
|
180
|
+
var PackageJson = fromJsonString(Struct({ name: String2 }));
|
|
181
|
+
var packageName = (root) => gen(function* () {
|
|
182
|
+
const fs = yield* FileSystem;
|
|
183
|
+
const path = yield* Path;
|
|
184
|
+
return yield* fs.readFileString(path.join(root, "package.json")).pipe(flatMap(decodeEffect(PackageJson)), map3((manifest) => manifest.name), mapError(() => new DeclarationsInvalid({ reason: "package.json has no name" })));
|
|
185
|
+
});
|
|
186
|
+
var duplicateLoopId = (loops) => loops.map((loop) => loop.id).find((id, index, ids) => ids.indexOf(id) !== index);
|
|
187
|
+
var buildPackage = (directory) => gen(function* () {
|
|
188
|
+
const fs = yield* FileSystem;
|
|
189
|
+
const path = yield* Path;
|
|
190
|
+
const root = path.resolve(directory);
|
|
191
|
+
const source = yield* provenance(root);
|
|
192
|
+
const name = yield* packageName(root);
|
|
193
|
+
const installed = yield* run("bun", ["install", "--frozen-lockfile", "--ignore-scripts"], root).pipe(mapError((error) => new DependencyInstallFailed({ reason: error.message })));
|
|
194
|
+
if (!installed.ok)
|
|
195
|
+
return yield* new DependencyInstallFailed({ reason: failure(installed) });
|
|
196
|
+
const entry = path.join(root, ".kitman-build-entry.ts");
|
|
197
|
+
yield* acquireRelease(fs.writeFileString(entry, `import config from './kitman.config.ts'
|
|
198
|
+
import { runPackage } from '@kitman-sh/sdk/program'
|
|
199
|
+
|
|
200
|
+
runPackage(config)
|
|
201
|
+
`), () => ignore(fs.remove(entry)));
|
|
202
|
+
const out = yield* fs.makeTempDirectoryScoped({ prefix: "kitman-package-" });
|
|
203
|
+
const bundleFile = path.join(out, "bundle.js");
|
|
204
|
+
const bundled = yield* run("bun", ["build", entry, "--target=bun", "--format=esm", "--outfile", bundleFile], root);
|
|
205
|
+
if (!bundled.ok)
|
|
206
|
+
return yield* new BundleFailed({ reason: failure(bundled) });
|
|
207
|
+
const described = yield* run("bun", [bundleFile, describeFlag], out);
|
|
208
|
+
if (!described.ok)
|
|
209
|
+
return yield* new BundleFailed({ reason: `the bundle does not load: ${failure(described)}` });
|
|
210
|
+
const result = yield* decodeEffect(fromJsonString(toCodecJson(Described)))(described.stdout).pipe(mapError((error) => new BundleFailed({ reason: `the bundle described itself wrongly: ${error.message}` })));
|
|
211
|
+
if (isTagged(result, "Refused"))
|
|
212
|
+
return yield* result.error;
|
|
213
|
+
const duplicate = duplicateLoopId(result.loops);
|
|
214
|
+
if (duplicate !== undefined)
|
|
215
|
+
return yield* new DeclarationsInvalid({ reason: `Loop "${duplicate}" is declared twice` });
|
|
216
|
+
const agents = yield* decodeUnknownEffect(ConfigAgents)(result.agents).pipe(mapError((error) => new DeclarationsInvalid({ reason: error.message })));
|
|
217
|
+
const kits = result.kits === undefined ? undefined : yield* decodeUnknownEffect(ConfigKits)(result.kits).pipe(mapError((error) => new DeclarationsInvalid({ reason: error.message })));
|
|
218
|
+
const declarations = yield* decodeUnknownEffect(PackageDeclarations)({
|
|
219
|
+
loops: result.loops,
|
|
220
|
+
agents: yield* readAgents(root, agents),
|
|
221
|
+
...result.schedules === undefined ? undefined : { schedules: result.schedules },
|
|
222
|
+
...kits === undefined ? undefined : { kits: yield* readKits(root, kits) }
|
|
223
|
+
}).pipe(mapError((error) => new DeclarationsInvalid({ reason: error.message })));
|
|
224
|
+
const bundle = yield* fs.readFile(bundleFile).pipe(mapError((error) => new BundleFailed({ reason: error.message })));
|
|
225
|
+
return {
|
|
226
|
+
name,
|
|
227
|
+
bundle,
|
|
228
|
+
digest: digestSha256(bundle, "hex"),
|
|
229
|
+
declarations,
|
|
230
|
+
protocolVersion: RunnerRpcProtocolVersion,
|
|
231
|
+
provenance: source
|
|
232
|
+
};
|
|
233
|
+
}).pipe(scoped, catchTags({
|
|
234
|
+
PlatformError: (error) => fail4(new BundleFailed({ reason: error.message }))
|
|
235
|
+
}));
|
|
236
|
+
export {
|
|
237
|
+
BundleFailed,
|
|
238
|
+
DeclarationsInvalid,
|
|
239
|
+
DependencyInstallFailed,
|
|
240
|
+
buildPackage
|
|
241
|
+
};
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import {
|
|
3
|
+
declare,
|
|
4
|
+
optionalKey,
|
|
5
|
+
Literal,
|
|
6
|
+
Null,
|
|
7
|
+
String2,
|
|
8
|
+
Boolean2,
|
|
9
|
+
Struct,
|
|
10
|
+
Record,
|
|
11
|
+
ArraySchema,
|
|
12
|
+
Union,
|
|
13
|
+
Literals,
|
|
14
|
+
makeFilter,
|
|
15
|
+
isPattern,
|
|
16
|
+
Finite,
|
|
17
|
+
isGreaterThanOrEqualTo,
|
|
18
|
+
isLessThanOrEqualTo2,
|
|
19
|
+
Int,
|
|
20
|
+
isMinLength,
|
|
21
|
+
isMaxLength,
|
|
22
|
+
toEquivalence,
|
|
23
|
+
Json,
|
|
24
|
+
guard,
|
|
25
|
+
relativePathPattern,
|
|
26
|
+
skillNamePattern,
|
|
27
|
+
SafeJson,
|
|
28
|
+
AgentEfforts,
|
|
29
|
+
LoopDataSchemaRef,
|
|
30
|
+
KitKinds
|
|
31
|
+
} from "./chunk-txyq8r41.js";
|
|
32
|
+
|
|
33
|
+
// packages/core/src/schedule.ts
|
|
34
|
+
var ScheduleFrequency = ["daily", "weekly"];
|
|
35
|
+
var ScheduleMisfirePolicies = ["skip", "fire_once", "catch_up"];
|
|
36
|
+
var ScheduleOverlapPolicies = ["allow", "skip", "coalesce"];
|
|
37
|
+
var ScheduleVersionStatuses = ["draft", "published", "disabled", "archived"];
|
|
38
|
+
var ScheduleCalendarRule = Struct({
|
|
39
|
+
frequency: Literals(ScheduleFrequency),
|
|
40
|
+
hour: Int.check(isGreaterThanOrEqualTo(0), isLessThanOrEqualTo2(23)),
|
|
41
|
+
minute: Int.check(isGreaterThanOrEqualTo(0), isLessThanOrEqualTo2(59)),
|
|
42
|
+
second: optionalKey(Int.check(isGreaterThanOrEqualTo(0), isLessThanOrEqualTo2(59))),
|
|
43
|
+
daysOfWeek: optionalKey(ArraySchema(Int.check(isGreaterThanOrEqualTo(0), isLessThanOrEqualTo2(6))).check(isMinLength(1), isMaxLength(7)))
|
|
44
|
+
});
|
|
45
|
+
var ScheduleCronRule = Struct({
|
|
46
|
+
cron: String2.check(isMinLength(9), isMaxLength(200), isPattern(new RegExp("^[0-9*,/-]+( [0-9*,/-]+){4}$", "u")))
|
|
47
|
+
});
|
|
48
|
+
var ScheduleRule = Union([ScheduleCalendarRule, ScheduleCronRule]);
|
|
49
|
+
var cronBounds = [
|
|
50
|
+
[0, 59],
|
|
51
|
+
[0, 23],
|
|
52
|
+
[1, 31],
|
|
53
|
+
[1, 12],
|
|
54
|
+
[0, 7]
|
|
55
|
+
];
|
|
56
|
+
function cronField(field, [min, max]) {
|
|
57
|
+
const values = new Set;
|
|
58
|
+
for (const part of field.split(",")) {
|
|
59
|
+
const match = /^(\*|(\d+)(?:-(\d+))?)(?:\/(\d+))?$/.exec(part);
|
|
60
|
+
if (match === null)
|
|
61
|
+
return;
|
|
62
|
+
const from = match[1] === "*" ? min : Number(match[2]);
|
|
63
|
+
const to = match[1] === "*" ? max : match[3] === undefined ? match[4] === undefined ? from : max : Number(match[3]);
|
|
64
|
+
const step = match[4] === undefined ? 1 : Number(match[4]);
|
|
65
|
+
if (from < min || to > max || from > to || step < 1)
|
|
66
|
+
return;
|
|
67
|
+
for (let value = from;value <= to; value += step)
|
|
68
|
+
values.add(value);
|
|
69
|
+
}
|
|
70
|
+
return values;
|
|
71
|
+
}
|
|
72
|
+
function parseCron(cron) {
|
|
73
|
+
const fields = cron.split(" ");
|
|
74
|
+
const [minutes, hours, days, months, weekdays] = fields.map((field, index) => cronField(field, cronBounds[index] ?? [0, 0]));
|
|
75
|
+
if (fields.length !== 5 || !minutes || !hours || !days || !months || !weekdays)
|
|
76
|
+
return;
|
|
77
|
+
return {
|
|
78
|
+
minutes,
|
|
79
|
+
hours,
|
|
80
|
+
days,
|
|
81
|
+
months,
|
|
82
|
+
weekdays: new Set([...weekdays].map((value) => value % 7)),
|
|
83
|
+
dayRestricted: !(fields[2] ?? "").startsWith("*"),
|
|
84
|
+
weekdayRestricted: !(fields[4] ?? "").startsWith("*")
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
function isScheduleRule(value) {
|
|
88
|
+
return guard(ScheduleRule)(value) && (!("cron" in value) || parseCron(value.cron) !== undefined);
|
|
89
|
+
}
|
|
90
|
+
var ScheduleVersion = Struct({
|
|
91
|
+
contractVersion: Literal("schedule.v1"),
|
|
92
|
+
id: String2.check(isMinLength(1)),
|
|
93
|
+
scheduleId: String2.check(isMinLength(1)),
|
|
94
|
+
workspaceId: String2.check(isMinLength(1)),
|
|
95
|
+
projectId: optionalKey(String2.check(isMinLength(1))),
|
|
96
|
+
loopId: optionalKey(String2.check(isMinLength(1))),
|
|
97
|
+
name: optionalKey(String2.check(isMinLength(1), isMaxLength(200))),
|
|
98
|
+
version: Int.check(isGreaterThanOrEqualTo(1)),
|
|
99
|
+
status: Literals(ScheduleVersionStatuses),
|
|
100
|
+
timezone: String2.check(isMinLength(1), isMaxLength(80)),
|
|
101
|
+
rule: ScheduleRule,
|
|
102
|
+
misfirePolicy: Literals(ScheduleMisfirePolicies),
|
|
103
|
+
overlapPolicy: Literals(ScheduleOverlapPolicies),
|
|
104
|
+
maxCatchUp: Int.check(isGreaterThanOrEqualTo(0), isLessThanOrEqualTo2(200)),
|
|
105
|
+
misfireGraceSeconds: optionalKey(Int.check(isGreaterThanOrEqualTo(0), isLessThanOrEqualTo2(604800))),
|
|
106
|
+
inputSchemaRef: optionalKey(LoopDataSchemaRef),
|
|
107
|
+
input: optionalKey(SafeJson),
|
|
108
|
+
createdAt: String2.check(isMinLength(1))
|
|
109
|
+
});
|
|
110
|
+
var zones = new Map;
|
|
111
|
+
var resolvedLocalDateTimes = new Map;
|
|
112
|
+
|
|
113
|
+
// packages/core/src/package-declarations.ts
|
|
114
|
+
var LoopCapabilities = [
|
|
115
|
+
"agent_work",
|
|
116
|
+
"ask",
|
|
117
|
+
"call",
|
|
118
|
+
"verify",
|
|
119
|
+
"change_request",
|
|
120
|
+
"write_back",
|
|
121
|
+
"post_comment",
|
|
122
|
+
"create_tasks",
|
|
123
|
+
"merge_change_request",
|
|
124
|
+
"publish_release"
|
|
125
|
+
];
|
|
126
|
+
var JsonObject = Record(String2, Json);
|
|
127
|
+
var recordKeyedBy = (pattern, value) => Record(String2, value).check(makeFilter((record) => {
|
|
128
|
+
const bad = Object.keys(record).find((key) => !new RegExp(pattern).test(key));
|
|
129
|
+
return bad === undefined ? true : `${JSON.stringify(bad)} is not a valid name or relative path`;
|
|
130
|
+
}));
|
|
131
|
+
var SecretName = String2.check(isPattern(/^[A-Za-z_][A-Za-z0-9_]{0,127}$/));
|
|
132
|
+
var EventFilterValue = Union([String2, Finite, Boolean2, Null]);
|
|
133
|
+
var LoopManifest = Struct({
|
|
134
|
+
id: String2,
|
|
135
|
+
title: String2,
|
|
136
|
+
input: JsonObject,
|
|
137
|
+
output: JsonObject,
|
|
138
|
+
outcome: optionalKey(Literals(["feature", "bug", "refactor", "investigation", "docs", "migration"])),
|
|
139
|
+
agents: Record(String2, String2),
|
|
140
|
+
checkout: Literals(["none", "read", "write"]),
|
|
141
|
+
when: ArraySchema(Struct({
|
|
142
|
+
event: String2,
|
|
143
|
+
filter: optionalKey(Record(String2, Union([EventFilterValue, ArraySchema(EventFilterValue)]))),
|
|
144
|
+
input: Record(String2, String2)
|
|
145
|
+
})),
|
|
146
|
+
offers: ArraySchema(Struct({ id: String2, title: String2, loop: String2 })),
|
|
147
|
+
capabilities: ArraySchema(Literals(LoopCapabilities)),
|
|
148
|
+
secrets: optionalKey(ArraySchema(SecretName))
|
|
149
|
+
});
|
|
150
|
+
var AgentDeclaration = Struct({
|
|
151
|
+
extends: optionalKey(String2),
|
|
152
|
+
instructions: optionalKey(String2),
|
|
153
|
+
harness: optionalKey(String2),
|
|
154
|
+
model: optionalKey(String2),
|
|
155
|
+
effort: optionalKey(Literals(AgentEfforts)),
|
|
156
|
+
kits: optionalKey(ArraySchema(String2)),
|
|
157
|
+
network: optionalKey(Union([Struct({ hosts: ArraySchema(String2) }), Literal("open")])),
|
|
158
|
+
sandbox: optionalKey(Literal("docker"))
|
|
159
|
+
});
|
|
160
|
+
var scheduleFields = {
|
|
161
|
+
name: String2.check(isMinLength(1)),
|
|
162
|
+
loop: String2,
|
|
163
|
+
project: optionalKey(String2),
|
|
164
|
+
input: optionalKey(JsonObject),
|
|
165
|
+
timezone: String2,
|
|
166
|
+
misfire: optionalKey(Literals(ScheduleMisfirePolicies)),
|
|
167
|
+
overlap: optionalKey(Literals(ScheduleOverlapPolicies))
|
|
168
|
+
};
|
|
169
|
+
var ScheduleDeclaration = Union([
|
|
170
|
+
Struct({
|
|
171
|
+
...scheduleFields,
|
|
172
|
+
cron: String2.check(makeFilter((cron) => isScheduleRule({ cron }) || "five cron fields, each within its range"))
|
|
173
|
+
}),
|
|
174
|
+
Struct({
|
|
175
|
+
...scheduleFields,
|
|
176
|
+
rule: declare((value) => isScheduleRule(value), {
|
|
177
|
+
expected: "a Schedule rule: frequency daily or weekly, hour, minute, and optionally second and daysOfWeek"
|
|
178
|
+
})
|
|
179
|
+
})
|
|
180
|
+
]);
|
|
181
|
+
var AuthoredKitDeclaration = Struct({
|
|
182
|
+
name: String2.check(isMinLength(1)),
|
|
183
|
+
kind: optionalKey(Literals(KitKinds)),
|
|
184
|
+
description: optionalKey(String2),
|
|
185
|
+
context: String2,
|
|
186
|
+
skills: optionalKey(recordKeyedBy(skillNamePattern, recordKeyedBy(relativePathPattern, String2)))
|
|
187
|
+
});
|
|
188
|
+
var KitInstallationDeclaration = Struct({
|
|
189
|
+
source: String2.check(isMinLength(1)),
|
|
190
|
+
version: optionalKey(String2)
|
|
191
|
+
});
|
|
192
|
+
var KitAssignmentDeclaration = Struct({
|
|
193
|
+
kit: String2.check(isMinLength(1)),
|
|
194
|
+
workspace: optionalKey(Literals(["default", "mandatory"])),
|
|
195
|
+
projects: optionalKey(ArraySchema(String2))
|
|
196
|
+
});
|
|
197
|
+
var KitDeclaration = Union([
|
|
198
|
+
KitInstallationDeclaration,
|
|
199
|
+
KitAssignmentDeclaration,
|
|
200
|
+
AuthoredKitDeclaration
|
|
201
|
+
]);
|
|
202
|
+
var PackageDeclarations = Struct({
|
|
203
|
+
loops: ArraySchema(LoopManifest),
|
|
204
|
+
agents: Record(String2, AgentDeclaration),
|
|
205
|
+
schedules: optionalKey(Record(String2, ScheduleDeclaration)),
|
|
206
|
+
kits: optionalKey(Record(String2, KitDeclaration))
|
|
207
|
+
});
|
|
208
|
+
var sameLoop = toEquivalence(LoopManifest);
|
|
209
|
+
var sameAgent = toEquivalence(AgentDeclaration);
|
|
210
|
+
|
|
211
|
+
export { LoopCapabilities, LoopManifest, AgentDeclaration, KitInstallationDeclaration, KitAssignmentDeclaration, PackageDeclarations };
|