@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.
@@ -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 };