@kitman-sh/cli 0.9.0 → 0.10.53
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-11p4wf6n.js +3551 -0
- package/dist/chunk-1mc9vgcr.js +39 -0
- package/dist/chunk-30397r95.js +30 -0
- package/dist/chunk-3bj7sc3v.js +389 -0
- package/dist/chunk-6vns3ej0.js +23 -0
- package/dist/chunk-7thnf14y.js +936 -0
- package/dist/chunk-arvwar2c.js +141 -0
- package/dist/chunk-b6thzgc9.js +32 -0
- package/dist/{chunk-8bvf4fh4.js → chunk-ctasxxz5.js} +26 -11
- package/dist/{chunk-5gjpv3ax.js → chunk-dzh9e6n2.js} +824 -651
- package/dist/{chunk-snn0e1qb.js → chunk-eg8f5ncv.js} +7 -3
- package/dist/chunk-g5bs3f6z.js +173 -0
- package/dist/chunk-jafetf7z.js +109 -0
- package/dist/chunk-jagzz148.js +527 -0
- package/dist/{chunk-1d4316hp.js → chunk-jfvq7s24.js} +38 -25
- package/dist/chunk-mbctzx7e.js +11436 -0
- package/dist/chunk-mej2bx5n.js +100 -0
- package/dist/chunk-p6spvbwq.js +6305 -0
- package/dist/chunk-pp1p3g6e.js +133 -0
- package/dist/chunk-r8p3nxcp.js +231 -0
- package/dist/chunk-txwt6r25.js +1731 -0
- package/dist/chunk-v290mf51.js +5242 -0
- package/dist/chunk-vjmz23rs.js +13 -0
- package/dist/chunk-vyv0p5eq.js +3183 -0
- package/dist/chunk-wh1pa2aa.js +15322 -0
- package/dist/chunk-x0b92bjb.js +222 -0
- package/dist/{chunk-8z5b6fpd.js → chunk-x9dhxfts.js} +216 -152
- package/dist/chunk-z821b2gp.js +164 -0
- package/dist/index.js +13 -5738
- package/dist/opencode-reader.main.ts +4 -0
- package/package.json +6 -5
- package/dist/chunk-3gxahgnq.js +0 -28495
- package/dist/chunk-ehzbtavj.js +0 -247
- package/dist/chunk-f5z8tgss.js +0 -1214
- package/dist/chunk-kdb1cbnx.js +0 -1273
- package/dist/chunk-ke1w0hx7.js +0 -5771
- package/dist/chunk-z6hc4ew9.js +0 -13
|
@@ -0,0 +1,527 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import {
|
|
3
|
+
isString2,
|
|
4
|
+
hasProperty,
|
|
5
|
+
isTagged,
|
|
6
|
+
Reference,
|
|
7
|
+
all3,
|
|
8
|
+
forEach,
|
|
9
|
+
succeed6,
|
|
10
|
+
gen,
|
|
11
|
+
fail7,
|
|
12
|
+
flatMap3,
|
|
13
|
+
map8,
|
|
14
|
+
catchTags,
|
|
15
|
+
mapError2,
|
|
16
|
+
orDie,
|
|
17
|
+
ignore,
|
|
18
|
+
orElseSucceed,
|
|
19
|
+
provide3,
|
|
20
|
+
scoped,
|
|
21
|
+
acquireRelease,
|
|
22
|
+
encode2,
|
|
23
|
+
decodeUnknownEffect2,
|
|
24
|
+
decodeEffect,
|
|
25
|
+
optionalKey,
|
|
26
|
+
String4,
|
|
27
|
+
Struct,
|
|
28
|
+
Record,
|
|
29
|
+
Union,
|
|
30
|
+
fromJsonString,
|
|
31
|
+
TaggedError2,
|
|
32
|
+
toCodecJson,
|
|
33
|
+
Json,
|
|
34
|
+
encodePrettyJsonString
|
|
35
|
+
} from "./chunk-mbctzx7e.js";
|
|
36
|
+
import"./chunk-arvwar2c.js";
|
|
37
|
+
import {
|
|
38
|
+
canonicalJson,
|
|
39
|
+
digestSha256,
|
|
40
|
+
schemaBodyJson,
|
|
41
|
+
filterStatusOk,
|
|
42
|
+
get2,
|
|
43
|
+
layer2,
|
|
44
|
+
kitmanMcpServer,
|
|
45
|
+
RunnerRpcProtocolVersion
|
|
46
|
+
} from "./chunk-wh1pa2aa.js";
|
|
47
|
+
import {
|
|
48
|
+
decodeText,
|
|
49
|
+
mkString,
|
|
50
|
+
FileSystem,
|
|
51
|
+
Path,
|
|
52
|
+
withDefault,
|
|
53
|
+
String2
|
|
54
|
+
} from "./chunk-11p4wf6n.js";
|
|
55
|
+
import {
|
|
56
|
+
Packument,
|
|
57
|
+
tarballMatches
|
|
58
|
+
} from "./chunk-g5bs3f6z.js";
|
|
59
|
+
import"./chunk-pp1p3g6e.js";
|
|
60
|
+
import"./chunk-ctasxxz5.js";
|
|
61
|
+
import {
|
|
62
|
+
AgentDeclaration,
|
|
63
|
+
KitDeclarations
|
|
64
|
+
} from "./chunk-txwt6r25.js";
|
|
65
|
+
import {
|
|
66
|
+
describeFlag,
|
|
67
|
+
Described
|
|
68
|
+
} from "./chunk-jfvq7s24.js";
|
|
69
|
+
import"./chunk-x9dhxfts.js";
|
|
70
|
+
import {
|
|
71
|
+
ChildProcessSpawner,
|
|
72
|
+
make7
|
|
73
|
+
} from "./chunk-3bj7sc3v.js";
|
|
74
|
+
import"./chunk-1mc9vgcr.js";
|
|
75
|
+
import"./chunk-z821b2gp.js";
|
|
76
|
+
|
|
77
|
+
// packages/sdk/src/build/index.ts
|
|
78
|
+
class DependencyInstallFailed extends TaggedError2()("DependencyInstallFailed", {
|
|
79
|
+
reason: String4
|
|
80
|
+
}) {
|
|
81
|
+
get message() {
|
|
82
|
+
return `Dependencies do not install from the lockfile: ${this.reason}`;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
class BundleFailed extends TaggedError2()("BundleFailed", { reason: String4 }) {
|
|
87
|
+
get message() {
|
|
88
|
+
return `The Kit does not bundle: ${this.reason}`;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
class DeclarationsInvalid extends TaggedError2()("DeclarationsInvalid", {
|
|
93
|
+
reason: String4
|
|
94
|
+
}) {
|
|
95
|
+
get message() {
|
|
96
|
+
return `The Kit's declarations are invalid: ${this.reason}`;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
class SourceFetchFailed extends TaggedError2()("SourceFetchFailed", {
|
|
101
|
+
reason: String4
|
|
102
|
+
}) {
|
|
103
|
+
get message() {
|
|
104
|
+
return `A setup source does not fetch: ${this.reason}`;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
var RepositoryText = Union([String4, Struct({ file: String4 })]);
|
|
108
|
+
var ConfigAgents = Record(String4, Struct({
|
|
109
|
+
...AgentDeclaration.fields,
|
|
110
|
+
instructions: optionalKey(RepositoryText)
|
|
111
|
+
}));
|
|
112
|
+
var run = (command, args, cwd) => gen(function* () {
|
|
113
|
+
const spawner = yield* ChildProcessSpawner;
|
|
114
|
+
const handle = yield* spawner.spawn(make7(command, args, { cwd, stdin: "ignore" }));
|
|
115
|
+
const [stdout, stderr, exitCode] = yield* all3([
|
|
116
|
+
mkString(decodeText(handle.stdout)),
|
|
117
|
+
mkString(decodeText(handle.stderr)),
|
|
118
|
+
handle.exitCode
|
|
119
|
+
], { concurrency: 3 });
|
|
120
|
+
return { stdout, stderr, ok: exitCode === 0 };
|
|
121
|
+
}).pipe(scoped);
|
|
122
|
+
var failure = (result) => (result.stderr.trim() || result.stdout.trim()).slice(-2000);
|
|
123
|
+
var provenance = (directory) => gen(function* () {
|
|
124
|
+
const git = (...args) => run("git", args, directory).pipe(map8((result) => result.ok ? result.stdout.trim() : undefined), orElseSucceed(() => {
|
|
125
|
+
return;
|
|
126
|
+
}));
|
|
127
|
+
const repository = yield* git("remote", "get-url", "origin");
|
|
128
|
+
const commit = yield* git("rev-parse", "HEAD");
|
|
129
|
+
const status = yield* git("status", "--porcelain");
|
|
130
|
+
return {
|
|
131
|
+
...repository ? { repository } : undefined,
|
|
132
|
+
...commit ? { commit } : undefined,
|
|
133
|
+
clean: commit !== undefined && status === ""
|
|
134
|
+
};
|
|
135
|
+
});
|
|
136
|
+
var inKit = (directory, file, what) => gen(function* () {
|
|
137
|
+
const path = yield* Path;
|
|
138
|
+
const resolved = path.resolve(directory, file);
|
|
139
|
+
if (path.relative(directory, resolved).startsWith(".."))
|
|
140
|
+
return yield* new DeclarationsInvalid({ reason: `${what} ${file} is outside the Kit` });
|
|
141
|
+
return resolved;
|
|
142
|
+
});
|
|
143
|
+
var readText = (directory, text, what) => gen(function* () {
|
|
144
|
+
if (isString2(text))
|
|
145
|
+
return text;
|
|
146
|
+
const fs = yield* FileSystem;
|
|
147
|
+
const file = yield* inKit(directory, text.file, what);
|
|
148
|
+
return yield* fs.readFileString(file).pipe(mapError2(() => new DeclarationsInvalid({ reason: `${what} ${text.file} does not read` })));
|
|
149
|
+
});
|
|
150
|
+
var readAgents = (directory, agents) => forEach(Object.entries(agents), ([id, { instructions, ...agent }]) => instructions === undefined ? succeed6([id, agent]) : map8(readText(directory, instructions, `Agent "${id}" instructions`), (text) => [id, { ...agent, instructions: text.trim() }])).pipe(map8(Object.fromEntries));
|
|
151
|
+
var utf8 = new TextDecoder("utf-8", { fatal: true });
|
|
152
|
+
var setupFile = (bytes) => {
|
|
153
|
+
try {
|
|
154
|
+
const text = utf8.decode(bytes);
|
|
155
|
+
return text.includes("\x00") ? { base64: encode2(bytes) } : { utf8: text };
|
|
156
|
+
} catch {
|
|
157
|
+
return { base64: encode2(bytes) };
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
var confined = (boundary, file, what) => gen(function* () {
|
|
161
|
+
const fs = yield* FileSystem;
|
|
162
|
+
const path = yield* Path;
|
|
163
|
+
const unreadable = () => new DeclarationsInvalid({ reason: `${what} does not read` });
|
|
164
|
+
const real = yield* fs.realPath(path.join(boundary, file)).pipe(mapError2(unreadable));
|
|
165
|
+
if (path.relative(yield* fs.realPath(boundary).pipe(mapError2(unreadable)), real).startsWith(".."))
|
|
166
|
+
return yield* new DeclarationsInvalid({ reason: `${what}: ${file} links outside its source` });
|
|
167
|
+
return real;
|
|
168
|
+
});
|
|
169
|
+
var readTree = (root, what, fetched = false) => gen(function* () {
|
|
170
|
+
const fs = yield* FileSystem;
|
|
171
|
+
const path = yield* Path;
|
|
172
|
+
const unreadable = () => new DeclarationsInvalid({ reason: `${what} does not read` });
|
|
173
|
+
const entries = yield* fs.readDirectory(root, { recursive: true }).pipe(mapError2(unreadable));
|
|
174
|
+
const files = {};
|
|
175
|
+
for (const entry of entries.toSorted()) {
|
|
176
|
+
const relative = entry.split(path.sep).join("/");
|
|
177
|
+
if (relative === ".git" || relative.startsWith(".git/"))
|
|
178
|
+
continue;
|
|
179
|
+
const file = fetched ? yield* confined(root, entry, what) : path.join(root, entry);
|
|
180
|
+
if ((yield* fs.stat(file).pipe(mapError2(unreadable))).type !== "File")
|
|
181
|
+
continue;
|
|
182
|
+
files[relative] = yield* fs.readFile(file).pipe(mapError2(unreadable));
|
|
183
|
+
}
|
|
184
|
+
return files;
|
|
185
|
+
});
|
|
186
|
+
var licenseFiles = ["LICENSE", "LICENSE.md", "LICENSE.txt", "COPYING"];
|
|
187
|
+
var fetchedTree = (root, path, what) => gen(function* () {
|
|
188
|
+
const fs = yield* FileSystem;
|
|
189
|
+
const paths = yield* Path;
|
|
190
|
+
const tree = yield* readTree(path === undefined ? root : yield* confined(root, path, what), what, true);
|
|
191
|
+
if (path === undefined)
|
|
192
|
+
return tree;
|
|
193
|
+
for (const license of licenseFiles)
|
|
194
|
+
if (tree[license] === undefined && (yield* fs.exists(paths.join(root, license))))
|
|
195
|
+
return { ...tree, [license]: yield* fs.readFile(yield* confined(root, license, what)).pipe(orDie) };
|
|
196
|
+
return tree;
|
|
197
|
+
});
|
|
198
|
+
var GitSourceLocation = Reference("kitman/sdk/build/GitSourceLocation", { defaultValue: () => (declared) => declared });
|
|
199
|
+
var fetchGit = (declared, what) => gen(function* () {
|
|
200
|
+
const fs = yield* FileSystem;
|
|
201
|
+
const { url, ref } = (yield* GitSourceLocation)(declared);
|
|
202
|
+
const checkout = yield* fs.makeTempDirectoryScoped({ prefix: "kitman-git-" });
|
|
203
|
+
for (const args of [
|
|
204
|
+
["init", "--quiet"],
|
|
205
|
+
["fetch", "--quiet", "--depth", "1", "--", url, ref ?? "HEAD"],
|
|
206
|
+
["checkout", "--quiet", "FETCH_HEAD"]
|
|
207
|
+
]) {
|
|
208
|
+
const result = yield* run("git", args, checkout);
|
|
209
|
+
if (!result.ok)
|
|
210
|
+
return yield* new SourceFetchFailed({
|
|
211
|
+
reason: `${what}: git ${url}${ref === undefined ? "" : ` at ${ref}`}: ${failure(result)}`
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
return checkout;
|
|
215
|
+
});
|
|
216
|
+
var fetchNpm = (name, wanted, what) => gen(function* () {
|
|
217
|
+
const fs = yield* FileSystem;
|
|
218
|
+
const path = yield* Path;
|
|
219
|
+
const registry = yield* String2("NPM_CONFIG_REGISTRY").pipe(withDefault("https://registry.npmjs.org"), orDie);
|
|
220
|
+
const failed = (reason) => new SourceFetchFailed({ reason: `${what}: npm ${name}@${wanted}: ${reason}` });
|
|
221
|
+
const packument = yield* get2(`${registry.replace(/\/+$/, "")}/${name.replace("/", "%2F")}`).pipe(flatMap3(filterStatusOk), flatMap3(schemaBodyJson(Packument)), mapError2((error) => failed(error.message)));
|
|
222
|
+
const dist = packument.versions[packument["dist-tags"][wanted] ?? wanted]?.dist;
|
|
223
|
+
if (dist === undefined)
|
|
224
|
+
return yield* failed("npm has no such version or dist-tag");
|
|
225
|
+
const tarball = yield* get2(dist.tarball).pipe(flatMap3(filterStatusOk), flatMap3((response) => response.arrayBuffer), map8((buffer) => new Uint8Array(buffer)), mapError2((error) => failed(error.message)));
|
|
226
|
+
if (!tarballMatches(tarball, dist))
|
|
227
|
+
return yield* failed(`the tarball does not match its integrity ${dist.integrity ?? `sha1 ${dist.shasum}`}`);
|
|
228
|
+
const directory = yield* fs.makeTempDirectoryScoped({ prefix: "kitman-npm-" });
|
|
229
|
+
yield* fs.writeFile(path.join(directory, "package.tgz"), tarball).pipe(orDie);
|
|
230
|
+
const extracted = yield* run("tar", ["-xzf", "package.tgz"], directory);
|
|
231
|
+
if (!extracted.ok)
|
|
232
|
+
return yield* failed(`the tarball does not extract: ${failure(extracted)}`);
|
|
233
|
+
return yield* confined(directory, "package", what);
|
|
234
|
+
}).pipe(provide3(layer2));
|
|
235
|
+
var sourceTree = (directory, source, what, checkouts) => gen(function* () {
|
|
236
|
+
switch (source.kind) {
|
|
237
|
+
case "local_path":
|
|
238
|
+
return yield* readTree(yield* inKit(directory, source.path, what), what);
|
|
239
|
+
case "git": {
|
|
240
|
+
const key = `${source.url}#${source.ref ?? ""}`;
|
|
241
|
+
const checkout = checkouts.get(key) ?? (yield* fetchGit({ url: source.url, ref: source.ref }, what));
|
|
242
|
+
checkouts.set(key, checkout);
|
|
243
|
+
return yield* fetchedTree(checkout, "path" in source ? source.path : undefined, what);
|
|
244
|
+
}
|
|
245
|
+
case "package":
|
|
246
|
+
return yield* fetchedTree(yield* fetchNpm(source.packageName, source.version ?? "latest", what), "path" in source ? source.path : undefined, what);
|
|
247
|
+
default:
|
|
248
|
+
return yield* new DeclarationsInvalid({
|
|
249
|
+
reason: `${what} comes from a ${source.kind} source, which a build cannot copy in; use a local path, git or npm`
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
var setupArchive = (directory, kit, setup, checkouts) => gen(function* () {
|
|
254
|
+
const fs = yield* FileSystem;
|
|
255
|
+
const files = {};
|
|
256
|
+
const place = (prefix, tree) => {
|
|
257
|
+
for (const [file, bytes] of Object.entries(tree))
|
|
258
|
+
files[`${prefix}/${file}`] = setupFile(bytes);
|
|
259
|
+
return { kind: "local_path", path: prefix };
|
|
260
|
+
};
|
|
261
|
+
if (setup.instructions !== undefined) {
|
|
262
|
+
const what = `Kit ${kit} instructions`;
|
|
263
|
+
const file = yield* inKit(directory, setup.instructions, what);
|
|
264
|
+
files["instructions.md"] = setupFile(yield* fs.readFile(file).pipe(mapError2(() => new DeclarationsInvalid({ reason: `${what} do not read` }))));
|
|
265
|
+
}
|
|
266
|
+
const skills = setup.skills === undefined ? undefined : yield* forEach(setup.skills, (skill) => map8(sourceTree(directory, skill.source, `Kit ${kit} skill ${skill.name}`, checkouts), (tree) => ({
|
|
267
|
+
...skill,
|
|
268
|
+
source: place(`skills/${skill.name}`, tree)
|
|
269
|
+
})));
|
|
270
|
+
const plugins = setup.plugins === undefined ? undefined : yield* forEach(setup.plugins, (plugin) => map8(sourceTree(directory, plugin.sources[0], `Kit ${kit} plugin ${plugin.name}`, checkouts), (tree) => ({
|
|
271
|
+
...plugin,
|
|
272
|
+
sources: [place(`plugins/${plugin.name}`, tree)]
|
|
273
|
+
})));
|
|
274
|
+
const archive = {
|
|
275
|
+
setup: {
|
|
276
|
+
...setup,
|
|
277
|
+
...setup.instructions === undefined ? undefined : { instructions: "instructions.md" },
|
|
278
|
+
...skills === undefined ? undefined : { skills },
|
|
279
|
+
...plugins === undefined ? undefined : { plugins }
|
|
280
|
+
},
|
|
281
|
+
files
|
|
282
|
+
};
|
|
283
|
+
const bytes = new TextEncoder().encode(canonicalJson(archive));
|
|
284
|
+
return { digest: digestSha256(bytes, "hex"), archive: bytes };
|
|
285
|
+
});
|
|
286
|
+
var PackageJson = fromJsonString(Struct({
|
|
287
|
+
name: String4,
|
|
288
|
+
version: optionalKey(String4),
|
|
289
|
+
dependencies: optionalKey(Record(String4, String4))
|
|
290
|
+
}));
|
|
291
|
+
var readPackageJson = (directory) => gen(function* () {
|
|
292
|
+
const fs = yield* FileSystem;
|
|
293
|
+
const path = yield* Path;
|
|
294
|
+
return yield* fs.readFileString(path.join(directory, "package.json")).pipe(flatMap3(decodeEffect(PackageJson)), mapError2(() => new DeclarationsInvalid({ reason: `${directory}/package.json has no name` })));
|
|
295
|
+
});
|
|
296
|
+
var identityOf = (manifest) => ({
|
|
297
|
+
name: manifest.name,
|
|
298
|
+
version: manifest.version ?? "0.0.0"
|
|
299
|
+
});
|
|
300
|
+
var installedPackage = (name, directory) => gen(function* () {
|
|
301
|
+
const fs = yield* FileSystem;
|
|
302
|
+
const path = yield* Path;
|
|
303
|
+
for (let at = directory;; at = path.dirname(at)) {
|
|
304
|
+
const candidate = path.join(at, "node_modules", name);
|
|
305
|
+
if (yield* fs.exists(path.join(candidate, "package.json")))
|
|
306
|
+
return yield* fs.realPath(candidate);
|
|
307
|
+
if (path.dirname(at) === at)
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
var importedFile = (file, specifier) => gen(function* () {
|
|
312
|
+
const fs = yield* FileSystem;
|
|
313
|
+
const path = yield* Path;
|
|
314
|
+
const target = path.resolve(path.dirname(file), specifier);
|
|
315
|
+
for (const candidate of [target, `${target}.ts`, path.join(target, "kitman.config.ts")])
|
|
316
|
+
if (yield* fs.stat(candidate).pipe(map8((info) => info.type === "File"), orElseSucceed(() => false)))
|
|
317
|
+
return candidate;
|
|
318
|
+
return;
|
|
319
|
+
});
|
|
320
|
+
var packageDirectory = (file) => gen(function* () {
|
|
321
|
+
const fs = yield* FileSystem;
|
|
322
|
+
const path = yield* Path;
|
|
323
|
+
for (let at = path.dirname(file);; at = path.dirname(at)) {
|
|
324
|
+
if (yield* fs.exists(path.join(at, "package.json")).pipe(orElseSucceed(() => false)))
|
|
325
|
+
return at;
|
|
326
|
+
if (path.dirname(at) === at)
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
});
|
|
330
|
+
var kitModules = (root) => gen(function* () {
|
|
331
|
+
const fs = yield* FileSystem;
|
|
332
|
+
const path = yield* Path;
|
|
333
|
+
const found = [];
|
|
334
|
+
const visited = new Set;
|
|
335
|
+
const packages = new Set([root]);
|
|
336
|
+
const known = (directory) => packages.has(directory);
|
|
337
|
+
const visitPackage = (directory) => gen(function* () {
|
|
338
|
+
for (const name of Object.keys((yield* readPackageJson(directory)).dependencies ?? {})) {
|
|
339
|
+
const installed = yield* installedPackage(name, directory).pipe(orElseSucceed(() => {
|
|
340
|
+
return;
|
|
341
|
+
}));
|
|
342
|
+
const module = installed === undefined ? undefined : path.join(installed, "kitman.config.ts");
|
|
343
|
+
if (installed === undefined || module === undefined || known(installed))
|
|
344
|
+
continue;
|
|
345
|
+
if (!(yield* fs.exists(module).pipe(orElseSucceed(() => false))))
|
|
346
|
+
continue;
|
|
347
|
+
packages.add(installed);
|
|
348
|
+
found.push({ directory: installed, module, identity: identityOf(yield* readPackageJson(installed)) });
|
|
349
|
+
yield* visitPackage(installed);
|
|
350
|
+
yield* visitImports(module);
|
|
351
|
+
}
|
|
352
|
+
});
|
|
353
|
+
const visitImports = (file) => gen(function* () {
|
|
354
|
+
if (visited.has(file))
|
|
355
|
+
return;
|
|
356
|
+
visited.add(file);
|
|
357
|
+
const transpiled = yield* run("bun", ["build", "--no-bundle", file], root).pipe(map8((result) => result.ok ? result.stdout : ""), orElseSucceed(() => ""));
|
|
358
|
+
for (const [, specifier] of transpiled.matchAll(/\b(?:from|import)\s*"(\.{1,2}\/[^"]+)"/gu)) {
|
|
359
|
+
const module = specifier === undefined ? undefined : yield* importedFile(file, specifier);
|
|
360
|
+
if (module === undefined || visited.has(module))
|
|
361
|
+
continue;
|
|
362
|
+
const directory = yield* packageDirectory(module);
|
|
363
|
+
if (directory !== undefined && directory !== root) {
|
|
364
|
+
found.push({ directory, module, identity: identityOf(yield* readPackageJson(directory)) });
|
|
365
|
+
if (!known(directory)) {
|
|
366
|
+
packages.add(directory);
|
|
367
|
+
yield* visitPackage(directory);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
yield* visitImports(module);
|
|
371
|
+
}
|
|
372
|
+
});
|
|
373
|
+
yield* visitPackage(root);
|
|
374
|
+
yield* visitImports(path.join(root, "kitman.config.ts"));
|
|
375
|
+
return found;
|
|
376
|
+
});
|
|
377
|
+
var buildEntry = (identity, modules) => [
|
|
378
|
+
"import config from './kitman.config.ts'",
|
|
379
|
+
"import { runKit } from '@kitman-sh/sdk/program'",
|
|
380
|
+
...modules.map((kit, index) => `import * as kit${index} from ${JSON.stringify(kit.module)}`),
|
|
381
|
+
"",
|
|
382
|
+
`runKit(config, ${JSON.stringify(identity)}, [${modules.map((kit, index) => `[kit${index}.default, ${JSON.stringify(kit.identity)}]`).join(", ")}])`,
|
|
383
|
+
""
|
|
384
|
+
].join(`
|
|
385
|
+
`);
|
|
386
|
+
var renamedKey = (declarations, what, from, to) => {
|
|
387
|
+
const key = Object.keys(declarations ?? {}).find((key) => hasProperty(declarations?.[key], from));
|
|
388
|
+
return key === undefined ? undefined : new DeclarationsInvalid({ reason: `${what} "${key}" names \`${from}\`, which is now \`${to}\`` });
|
|
389
|
+
};
|
|
390
|
+
var resolveNames = (names) => {
|
|
391
|
+
const winners = new Map;
|
|
392
|
+
const overrides = [];
|
|
393
|
+
for (const named of names) {
|
|
394
|
+
const key = `${named.what}\x00${named.name}`;
|
|
395
|
+
const winner = winners.get(key);
|
|
396
|
+
if (winner === undefined)
|
|
397
|
+
winners.set(key, named.kit);
|
|
398
|
+
else if (winner === named.kit)
|
|
399
|
+
return new DeclarationsInvalid({ reason: `Kit ${named.kit} names ${named.what} ${named.name} twice` });
|
|
400
|
+
else
|
|
401
|
+
overrides.push({ what: named.what, name: named.name, winner, replaced: named.kit });
|
|
402
|
+
}
|
|
403
|
+
return { wins: (named) => winners.get(`${named.what}\x00${named.name}`) === named.kit, overrides };
|
|
404
|
+
};
|
|
405
|
+
var buildKit = (directory, options = {}) => gen(function* () {
|
|
406
|
+
const fs = yield* FileSystem;
|
|
407
|
+
const path = yield* Path;
|
|
408
|
+
const root = path.resolve(directory);
|
|
409
|
+
const source = yield* provenance(root);
|
|
410
|
+
const identity = { ...identityOf(yield* readPackageJson(root)), ...options };
|
|
411
|
+
const installed = yield* run("bun", ["install", "--frozen-lockfile", "--ignore-scripts"], root).pipe(mapError2((error) => new DependencyInstallFailed({ reason: error.message })));
|
|
412
|
+
if (!installed.ok)
|
|
413
|
+
return yield* new DependencyInstallFailed({ reason: failure(installed) });
|
|
414
|
+
const packages = yield* kitModules(root);
|
|
415
|
+
const entry = path.join(root, ".kitman-build-entry.ts");
|
|
416
|
+
yield* acquireRelease(fs.writeFileString(entry, buildEntry(identity, packages)), () => ignore(fs.remove(entry)));
|
|
417
|
+
const out = yield* fs.makeTempDirectoryScoped({ prefix: "kitman-kit-" });
|
|
418
|
+
const bundleFile = path.join(out, "bundle.js");
|
|
419
|
+
const bundled = yield* run("bun", ["build", entry, "--target=bun", "--format=esm", "--outfile", bundleFile], root);
|
|
420
|
+
if (!bundled.ok)
|
|
421
|
+
return yield* failure(bundled).includes('"defineConfig"') ? new DeclarationsInvalid({
|
|
422
|
+
reason: "defineConfig is now defineKit; import defineKit from @kitman-sh/sdk/loop"
|
|
423
|
+
}) : new BundleFailed({ reason: failure(bundled) });
|
|
424
|
+
const described = yield* run("bun", [bundleFile, describeFlag], out);
|
|
425
|
+
if (!described.ok)
|
|
426
|
+
return yield* new BundleFailed({ reason: `the bundle does not load: ${failure(described)}` });
|
|
427
|
+
const result = yield* decodeEffect(fromJsonString(toCodecJson(Described)))(described.stdout).pipe(mapError2((error) => new BundleFailed({ reason: `the bundle described itself wrongly: ${error.message}` })));
|
|
428
|
+
if (isTagged(result, "Refused"))
|
|
429
|
+
return yield* result.error;
|
|
430
|
+
const [own] = result.kits;
|
|
431
|
+
if (own === undefined)
|
|
432
|
+
return yield* new BundleFailed({ reason: "the bundle described no Kit" });
|
|
433
|
+
const renamed = renamedKey(own.schedules, "Schedule", "project", "team") ?? renamedKey(own.schedules, "Schedule", "codebase", "team");
|
|
434
|
+
if (renamed !== undefined)
|
|
435
|
+
return yield* renamed;
|
|
436
|
+
const directories = new Map([
|
|
437
|
+
[`${identity.name}@${identity.version}`, root],
|
|
438
|
+
...packages.map((kit) => [`${kit.identity.name}@${kit.identity.version}`, kit.directory])
|
|
439
|
+
]);
|
|
440
|
+
const kits = yield* forEach(result.kits, (kit) => gen(function* () {
|
|
441
|
+
const at = directories.get(`${kit.name}@${kit.version}`) ?? root;
|
|
442
|
+
const invalid = (error) => new DeclarationsInvalid({ reason: `Kit ${kit.name}: ${error.message}` });
|
|
443
|
+
const agents = yield* decodeUnknownEffect2(ConfigAgents)(kit.agents).pipe(mapError2(invalid));
|
|
444
|
+
return { ...kit, directory: at, agents: yield* readAgents(at, agents), setup: kit.setup ?? {} };
|
|
445
|
+
}));
|
|
446
|
+
const named = kits.flatMap((kit) => [
|
|
447
|
+
...kit.loops.map((loop) => ({ kit: kit.name, what: "Loop", name: loop.id })),
|
|
448
|
+
...Object.keys(kit.agents).map((agent) => ({ kit: kit.name, what: "Agent", name: agent })),
|
|
449
|
+
...(kit.setup.skills ?? []).map((skill) => ({ kit: kit.name, what: "skill", name: skill.name })),
|
|
450
|
+
...(kit.setup.plugins ?? []).map((plugin) => ({ kit: kit.name, what: "plugin", name: plugin.name })),
|
|
451
|
+
...(kit.setup.mcpServers ?? []).map((server) => ({ kit: kit.name, what: "MCP server", name: server.name }))
|
|
452
|
+
]);
|
|
453
|
+
const kitman = named.find((entry) => entry.what === "MCP server" && entry.name === kitmanMcpServer);
|
|
454
|
+
if (kitman !== undefined)
|
|
455
|
+
return yield* new DeclarationsInvalid({
|
|
456
|
+
reason: `Kit ${kitman.kit} declares an MCP server named ${kitmanMcpServer}, which Kitman provides`
|
|
457
|
+
});
|
|
458
|
+
const names = resolveNames(named);
|
|
459
|
+
if (isTagged(names, "DeclarationsInvalid"))
|
|
460
|
+
return yield* names;
|
|
461
|
+
const winning = kits.map((kit) => ({
|
|
462
|
+
...kit,
|
|
463
|
+
loops: kit.loops.filter((loop) => names.wins({ kit: kit.name, what: "Loop", name: loop.id })),
|
|
464
|
+
agents: Object.fromEntries(Object.entries(kit.agents).filter(([agent]) => names.wins({ kit: kit.name, what: "Agent", name: agent })))
|
|
465
|
+
}));
|
|
466
|
+
const checkouts = new Map;
|
|
467
|
+
const archives = yield* forEach(kits, (kit) => setupArchive(kit.directory, kit.name, kit.setup, checkouts));
|
|
468
|
+
const carried = winning.map((kit, index) => ({
|
|
469
|
+
name: kit.name,
|
|
470
|
+
version: kit.version,
|
|
471
|
+
setup: archives[index]?.digest ?? "",
|
|
472
|
+
loops: kit.loops.map((loop) => loop.id),
|
|
473
|
+
agents: Object.keys(kit.agents)
|
|
474
|
+
}));
|
|
475
|
+
const declarations = yield* decodeUnknownEffect2(KitDeclarations)({
|
|
476
|
+
loops: winning.flatMap((kit) => kit.loops),
|
|
477
|
+
agents: Object.assign({}, ...winning.map((kit) => kit.agents)),
|
|
478
|
+
...own.schedules === undefined ? undefined : { schedules: own.schedules },
|
|
479
|
+
carried
|
|
480
|
+
}).pipe(mapError2((error) => new DeclarationsInvalid({ reason: error.message })));
|
|
481
|
+
const bundle = yield* fs.readFile(bundleFile).pipe(mapError2((error) => new BundleFailed({ reason: error.message })));
|
|
482
|
+
return {
|
|
483
|
+
...identity,
|
|
484
|
+
bundle,
|
|
485
|
+
digest: digestSha256(bundle, "hex"),
|
|
486
|
+
declarations,
|
|
487
|
+
setupArchives: archives,
|
|
488
|
+
protocolVersion: RunnerRpcProtocolVersion,
|
|
489
|
+
provenance: source,
|
|
490
|
+
overrides: names.overrides
|
|
491
|
+
};
|
|
492
|
+
}).pipe(scoped, catchTags({
|
|
493
|
+
PlatformError: (error) => fail7(new BundleFailed({ reason: error.message }))
|
|
494
|
+
}));
|
|
495
|
+
var writeKit = (directory, built, out) => gen(function* () {
|
|
496
|
+
const fs = yield* FileSystem;
|
|
497
|
+
const path = yield* Path;
|
|
498
|
+
const inKit = (file) => path.relative(directory, path.join(out, file));
|
|
499
|
+
const setup = {};
|
|
500
|
+
yield* fs.makeDirectory(path.join(out, "setup"), { recursive: true });
|
|
501
|
+
yield* fs.writeFile(path.join(out, "bundle.js"), built.bundle);
|
|
502
|
+
yield* fs.writeFileString(path.join(out, "declarations.json"), yield* encodePrettyJsonString(built.declarations));
|
|
503
|
+
for (const { digest, archive } of built.setupArchives) {
|
|
504
|
+
yield* fs.writeFile(path.join(out, "setup", `${digest}.json`), archive);
|
|
505
|
+
setup[digest] = inKit(`setup/${digest}.json`);
|
|
506
|
+
}
|
|
507
|
+
const manifestPath = path.join(directory, "package.json");
|
|
508
|
+
const manifest = yield* fs.readFileString(manifestPath).pipe(flatMap3(decodeEffect(fromJsonString(Record(String4, Json)))));
|
|
509
|
+
const kitman = {
|
|
510
|
+
bundle: inKit("bundle.js"),
|
|
511
|
+
digest: built.digest,
|
|
512
|
+
protocolVersion: built.protocolVersion,
|
|
513
|
+
declarations: inKit("declarations.json"),
|
|
514
|
+
setup
|
|
515
|
+
};
|
|
516
|
+
yield* fs.writeFileString(manifestPath, `${yield* encodePrettyJsonString({ ...manifest, kitman })}
|
|
517
|
+
`);
|
|
518
|
+
});
|
|
519
|
+
export {
|
|
520
|
+
BundleFailed,
|
|
521
|
+
DeclarationsInvalid,
|
|
522
|
+
DependencyInstallFailed,
|
|
523
|
+
GitSourceLocation,
|
|
524
|
+
SourceFetchFailed,
|
|
525
|
+
buildKit,
|
|
526
|
+
writeKit
|
|
527
|
+
};
|
|
@@ -2,21 +2,20 @@
|
|
|
2
2
|
import {
|
|
3
3
|
getOrElse,
|
|
4
4
|
TaggedError,
|
|
5
|
-
currentTimeMillis,
|
|
6
5
|
forEach,
|
|
7
6
|
tryPromise,
|
|
8
|
-
|
|
7
|
+
sync2,
|
|
9
8
|
gen,
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
flatMap3,
|
|
10
|
+
andThen2,
|
|
11
|
+
map8,
|
|
13
12
|
scoped,
|
|
14
|
-
|
|
15
|
-
FileSystem,
|
|
13
|
+
makeFormatterStandardSchemaV1,
|
|
16
14
|
is,
|
|
17
15
|
encodeEffect,
|
|
18
16
|
optionalKey,
|
|
19
|
-
|
|
17
|
+
String4,
|
|
18
|
+
Struct,
|
|
20
19
|
Record,
|
|
21
20
|
ArraySchema,
|
|
22
21
|
Union,
|
|
@@ -24,8 +23,10 @@ import {
|
|
|
24
23
|
fromJsonString,
|
|
25
24
|
TaggedError2,
|
|
26
25
|
toCodecJson,
|
|
27
|
-
Json
|
|
28
|
-
|
|
26
|
+
Json
|
|
27
|
+
} from "./chunk-mbctzx7e.js";
|
|
28
|
+
import {
|
|
29
|
+
currentTimeMillis,
|
|
29
30
|
ProgramWorkUnit,
|
|
30
31
|
RunFileRefused,
|
|
31
32
|
runFileContentType,
|
|
@@ -35,15 +36,23 @@ import {
|
|
|
35
36
|
bodyUint8Array,
|
|
36
37
|
filterStatusOk,
|
|
37
38
|
HttpClient,
|
|
39
|
+
KitSetup,
|
|
38
40
|
RunnerRpcError
|
|
39
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-wh1pa2aa.js";
|
|
42
|
+
import {
|
|
43
|
+
guard
|
|
44
|
+
} from "./chunk-pp1p3g6e.js";
|
|
45
|
+
import {
|
|
46
|
+
runForEach,
|
|
47
|
+
FileSystem
|
|
48
|
+
} from "./chunk-11p4wf6n.js";
|
|
40
49
|
import {
|
|
41
50
|
LoopManifest,
|
|
42
51
|
ManifestInvalid,
|
|
43
|
-
|
|
52
|
+
make14,
|
|
44
53
|
Suspended,
|
|
45
54
|
LoopCheckError
|
|
46
|
-
} from "./chunk-
|
|
55
|
+
} from "./chunk-txwt6r25.js";
|
|
47
56
|
|
|
48
57
|
// packages/sdk/src/program/engine.ts
|
|
49
58
|
class JournalWriteFailed extends TaggedError("JournalWriteFailed") {
|
|
@@ -51,12 +60,13 @@ class JournalWriteFailed extends TaggedError("JournalWriteFailed") {
|
|
|
51
60
|
return `Journal write failed: ${this.cause.message}`;
|
|
52
61
|
}
|
|
53
62
|
}
|
|
54
|
-
var JournalEntries = Record(
|
|
63
|
+
var JournalEntries = Record(String4, Json);
|
|
55
64
|
var isSuspended = is(Suspended);
|
|
56
|
-
var emptyWorkflow =
|
|
65
|
+
var emptyWorkflow = make14("kitman-loop/none", { payload: {}, idempotencyKey: () => "none" });
|
|
57
66
|
var replayStatuses = new Set([401, 403, 409, 429]);
|
|
58
67
|
var isRunnerRpcError = is(RunnerRpcError);
|
|
59
68
|
var isRunFileRefused = is(RunFileRefused);
|
|
69
|
+
var issues = makeFormatterStandardSchemaV1();
|
|
60
70
|
var put2 = (target, contentType, body) => gen(function* () {
|
|
61
71
|
const response = yield* (yield* HttpClient).execute(put(target.url).pipe(bodyUint8Array(body, contentType), setHeaders(target.headers ?? {})));
|
|
62
72
|
return (yield* filterStatusOk(response)).headers.etag ?? "";
|
|
@@ -77,7 +87,7 @@ var uploadRunFile = (files, file) => gen(function* () {
|
|
|
77
87
|
const contentType = runFileContentType(file.name);
|
|
78
88
|
const byteSize = Number((yield* fs.stat(file.path)).size);
|
|
79
89
|
const hash = sha256Hasher();
|
|
80
|
-
yield* runForEach(fs.stream(file.path), (chunk) =>
|
|
90
|
+
yield* runForEach(fs.stream(file.path), (chunk) => sync2(() => hash.update(chunk)));
|
|
81
91
|
const { file: slotted, upload } = yield* files.createRunFile({
|
|
82
92
|
step: file.step,
|
|
83
93
|
name: file.name,
|
|
@@ -88,7 +98,7 @@ var uploadRunFile = (files, file) => gen(function* () {
|
|
|
88
98
|
});
|
|
89
99
|
if (upload === undefined)
|
|
90
100
|
return slotted;
|
|
91
|
-
return yield* upload.kind === "single" ? readRange(file.path, 0, byteSize).pipe(
|
|
101
|
+
return yield* upload.kind === "single" ? readRange(file.path, 0, byteSize).pipe(flatMap3((body) => put2(upload, contentType, body)), andThen2(files.completeRunFile({ fileId: slotted.id }))) : flatMap3(uploadParts(files, file.path, contentType, slotted.id, upload), (parts) => files.completeRunFile({ fileId: slotted.id, parts }));
|
|
92
102
|
});
|
|
93
103
|
var programLease = (work) => ({
|
|
94
104
|
workUnitId: work.id,
|
|
@@ -101,24 +111,27 @@ var programLease = (work) => ({
|
|
|
101
111
|
});
|
|
102
112
|
var rpcRunFiles = (rpc, lease) => ({
|
|
103
113
|
createRunFile: (file) => rpc.createRunFile({ lease, ...file }),
|
|
104
|
-
runFileParts: (request) =>
|
|
114
|
+
runFileParts: (request) => map8(rpc.runFileParts({ lease, ...request, partNumbers: [...request.partNumbers] }), ({ parts }) => parts),
|
|
105
115
|
completeRunFile: ({ parts, ...request }) => rpc.completeRunFile({ lease, ...request, ...parts === undefined ? undefined : { parts: [...parts] } })
|
|
106
116
|
});
|
|
107
117
|
|
|
108
118
|
// packages/sdk/src/program/host.ts
|
|
109
119
|
var describeFlag = "--kitman-describe";
|
|
120
|
+
var DescribedKit = Struct({
|
|
121
|
+
name: String4,
|
|
122
|
+
version: String4,
|
|
123
|
+
loops: ArraySchema(LoopManifest),
|
|
124
|
+
agents: Record(String4, Json),
|
|
125
|
+
schedules: optionalKey(Record(String4, Json)),
|
|
126
|
+
setup: optionalKey(KitSetup)
|
|
127
|
+
});
|
|
110
128
|
var Described = Union([
|
|
111
|
-
TaggedStruct("Described", {
|
|
112
|
-
loops: ArraySchema(LoopManifest),
|
|
113
|
-
agents: Record(String2, Json),
|
|
114
|
-
schedules: optionalKey(Record(String2, Json)),
|
|
115
|
-
kits: optionalKey(Record(String2, Json))
|
|
116
|
-
}),
|
|
129
|
+
TaggedStruct("Described", { kits: ArraySchema(DescribedKit) }),
|
|
117
130
|
TaggedStruct("Refused", { error: Union([ManifestInvalid, LoopCheckError]) })
|
|
118
131
|
]);
|
|
119
132
|
var encodeDescribed = encodeEffect(fromJsonString(toCodecJson(Described)));
|
|
120
133
|
|
|
121
|
-
class ProgramRefused extends TaggedError2()("ProgramRefused", { reason:
|
|
134
|
+
class ProgramRefused extends TaggedError2()("ProgramRefused", { reason: String4 }) {
|
|
122
135
|
get message() {
|
|
123
136
|
return this.reason;
|
|
124
137
|
}
|