@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,1731 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import {
|
|
3
|
+
dual,
|
|
4
|
+
hasProperty,
|
|
5
|
+
Prototype,
|
|
6
|
+
isNone,
|
|
7
|
+
Service2,
|
|
8
|
+
empty3,
|
|
9
|
+
add,
|
|
10
|
+
getOrUndefined2,
|
|
11
|
+
get4,
|
|
12
|
+
merge3,
|
|
13
|
+
Reference,
|
|
14
|
+
fromInputUnsafe,
|
|
15
|
+
toMillis,
|
|
16
|
+
TaggedClass,
|
|
17
|
+
encode,
|
|
18
|
+
isSuccess2,
|
|
19
|
+
addFinalizerExit,
|
|
20
|
+
effectDiscard,
|
|
21
|
+
hasInterruptsOnly,
|
|
22
|
+
combine2,
|
|
23
|
+
squash,
|
|
24
|
+
hasInterrupts2,
|
|
25
|
+
min2,
|
|
26
|
+
exponential,
|
|
27
|
+
spaced,
|
|
28
|
+
while_,
|
|
29
|
+
setInputType,
|
|
30
|
+
promise,
|
|
31
|
+
succeed6,
|
|
32
|
+
suspend3,
|
|
33
|
+
sync2,
|
|
34
|
+
void_3,
|
|
35
|
+
callback3,
|
|
36
|
+
gen,
|
|
37
|
+
fail7,
|
|
38
|
+
failCause3,
|
|
39
|
+
die3,
|
|
40
|
+
try_2,
|
|
41
|
+
yieldNow,
|
|
42
|
+
flatMap3,
|
|
43
|
+
andThen2,
|
|
44
|
+
tap2,
|
|
45
|
+
map8,
|
|
46
|
+
catch_,
|
|
47
|
+
catchTag,
|
|
48
|
+
mapError2,
|
|
49
|
+
orDie,
|
|
50
|
+
retry,
|
|
51
|
+
sandbox,
|
|
52
|
+
matchEffect2,
|
|
53
|
+
context,
|
|
54
|
+
contextWith,
|
|
55
|
+
provideContext2,
|
|
56
|
+
provideService,
|
|
57
|
+
acquireUseRelease,
|
|
58
|
+
onExit,
|
|
59
|
+
interruptible,
|
|
60
|
+
uninterruptibleMask2,
|
|
61
|
+
annotateCurrentSpan,
|
|
62
|
+
withSpan,
|
|
63
|
+
fnUntraced,
|
|
64
|
+
encode3,
|
|
65
|
+
transform,
|
|
66
|
+
encodeBase64Url,
|
|
67
|
+
decodeBase64UrlString,
|
|
68
|
+
transform2,
|
|
69
|
+
declare,
|
|
70
|
+
decodeUnknownEffect2,
|
|
71
|
+
decodeEffect,
|
|
72
|
+
decodeSync,
|
|
73
|
+
encodeUnknownEffect,
|
|
74
|
+
encodeEffect,
|
|
75
|
+
encodeSync,
|
|
76
|
+
isSchema,
|
|
77
|
+
optionalKey,
|
|
78
|
+
optional,
|
|
79
|
+
Literal,
|
|
80
|
+
Never,
|
|
81
|
+
Unknown,
|
|
82
|
+
Null,
|
|
83
|
+
String4,
|
|
84
|
+
Boolean2,
|
|
85
|
+
Void,
|
|
86
|
+
Struct,
|
|
87
|
+
Record,
|
|
88
|
+
Tuple2,
|
|
89
|
+
ArraySchema,
|
|
90
|
+
NonEmptyArray,
|
|
91
|
+
Union,
|
|
92
|
+
Literals,
|
|
93
|
+
decodeTo2,
|
|
94
|
+
tag,
|
|
95
|
+
makeFilter,
|
|
96
|
+
isPattern,
|
|
97
|
+
Finite,
|
|
98
|
+
isGreaterThanOrEqualTo,
|
|
99
|
+
isLessThanOrEqualTo,
|
|
100
|
+
Int,
|
|
101
|
+
isMinLength,
|
|
102
|
+
isMaxLength,
|
|
103
|
+
Defect,
|
|
104
|
+
fromJsonString,
|
|
105
|
+
Cause,
|
|
106
|
+
Exit,
|
|
107
|
+
Class2,
|
|
108
|
+
TaggedError2,
|
|
109
|
+
toEquivalence,
|
|
110
|
+
toJsonSchemaDocument,
|
|
111
|
+
toCodecJson,
|
|
112
|
+
Json
|
|
113
|
+
} from "./chunk-mbctzx7e.js";
|
|
114
|
+
import {
|
|
115
|
+
WebCrypto,
|
|
116
|
+
SafeJson,
|
|
117
|
+
AgentSandboxNetwork,
|
|
118
|
+
AgentEfforts,
|
|
119
|
+
AgentCapabilities,
|
|
120
|
+
recommendedDefault,
|
|
121
|
+
LoopDataSchemaRef,
|
|
122
|
+
LoopVersion,
|
|
123
|
+
ProgramLoop,
|
|
124
|
+
AgentFallback,
|
|
125
|
+
MeasureEvidence,
|
|
126
|
+
CatchUp,
|
|
127
|
+
ClaimResult
|
|
128
|
+
} from "./chunk-wh1pa2aa.js";
|
|
129
|
+
import {
|
|
130
|
+
getCurrent
|
|
131
|
+
} from "./chunk-11p4wf6n.js";
|
|
132
|
+
import {
|
|
133
|
+
guard
|
|
134
|
+
} from "./chunk-pp1p3g6e.js";
|
|
135
|
+
import {
|
|
136
|
+
splitQuestionOptions,
|
|
137
|
+
recommendationProblem,
|
|
138
|
+
questionAdvice
|
|
139
|
+
} from "./chunk-1mc9vgcr.js";
|
|
140
|
+
import {
|
|
141
|
+
KitName,
|
|
142
|
+
KitDigest
|
|
143
|
+
} from "./chunk-z821b2gp.js";
|
|
144
|
+
|
|
145
|
+
// node_modules/.bun/effect@4.1.2/node_modules/effect/dist/crypto/internal/webCrypto.js
|
|
146
|
+
var subtleUnavailable = () => new Error("crypto.subtle is unavailable; browsers expose it only in secure contexts");
|
|
147
|
+
|
|
148
|
+
// node_modules/.bun/effect@4.1.2/node_modules/effect/dist/crypto/internal/digest.js
|
|
149
|
+
var webCryptoDigest = (crypto, algorithm, data) => {
|
|
150
|
+
const implementation = algorithm.implementation;
|
|
151
|
+
if (implementation !== undefined) {
|
|
152
|
+
return sync2(() => implementation(data));
|
|
153
|
+
}
|
|
154
|
+
return suspend3(() => {
|
|
155
|
+
const subtle = crypto?.subtle;
|
|
156
|
+
if (subtle === undefined)
|
|
157
|
+
return die3(subtleUnavailable());
|
|
158
|
+
return promise(async () => new Uint8Array(await subtle.digest(algorithm.name, data)));
|
|
159
|
+
});
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
// node_modules/.bun/effect@4.1.2/node_modules/effect/dist/crypto/Digest.js
|
|
163
|
+
var sha256 = {
|
|
164
|
+
name: "SHA-256",
|
|
165
|
+
outputLength: 32,
|
|
166
|
+
implementation: undefined
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
// packages/core/src/schedule.ts
|
|
170
|
+
var ScheduleFrequency = ["daily", "weekly"];
|
|
171
|
+
var ScheduleMisfirePolicies = ["skip", "fire_once", "catch_up"];
|
|
172
|
+
var ScheduleOverlapPolicies = ["allow", "skip", "coalesce"];
|
|
173
|
+
var ScheduleVersionStatuses = ["draft", "published", "disabled", "archived"];
|
|
174
|
+
var ScheduleCalendarRule = Struct({
|
|
175
|
+
frequency: Literals(ScheduleFrequency),
|
|
176
|
+
hour: Int.check(isGreaterThanOrEqualTo(0), isLessThanOrEqualTo(23)),
|
|
177
|
+
minute: Int.check(isGreaterThanOrEqualTo(0), isLessThanOrEqualTo(59)),
|
|
178
|
+
second: optionalKey(Int.check(isGreaterThanOrEqualTo(0), isLessThanOrEqualTo(59))),
|
|
179
|
+
daysOfWeek: optionalKey(ArraySchema(Int.check(isGreaterThanOrEqualTo(0), isLessThanOrEqualTo(6))).check(isMinLength(1), isMaxLength(7)))
|
|
180
|
+
});
|
|
181
|
+
var ScheduleCronRule = Struct({
|
|
182
|
+
cron: String4.check(isMinLength(9), isMaxLength(200), isPattern(new RegExp("^[0-9*,/-]+( [0-9*,/-]+){4}$", "u")))
|
|
183
|
+
});
|
|
184
|
+
var ScheduleRule = Union([ScheduleCalendarRule, ScheduleCronRule]);
|
|
185
|
+
var cronBounds = [
|
|
186
|
+
[0, 59],
|
|
187
|
+
[0, 23],
|
|
188
|
+
[1, 31],
|
|
189
|
+
[1, 12],
|
|
190
|
+
[0, 7]
|
|
191
|
+
];
|
|
192
|
+
function cronField(field, [min, max]) {
|
|
193
|
+
const values = new Set;
|
|
194
|
+
for (const part of field.split(",")) {
|
|
195
|
+
const match = /^(\*|(\d+)(?:-(\d+))?)(?:\/(\d+))?$/.exec(part);
|
|
196
|
+
if (match === null)
|
|
197
|
+
return;
|
|
198
|
+
const from = match[1] === "*" ? min : Number(match[2]);
|
|
199
|
+
const to = match[1] === "*" ? max : match[3] === undefined ? match[4] === undefined ? from : max : Number(match[3]);
|
|
200
|
+
const step = match[4] === undefined ? 1 : Number(match[4]);
|
|
201
|
+
if (from < min || to > max || from > to || step < 1)
|
|
202
|
+
return;
|
|
203
|
+
for (let value = from;value <= to; value += step)
|
|
204
|
+
values.add(value);
|
|
205
|
+
}
|
|
206
|
+
return values;
|
|
207
|
+
}
|
|
208
|
+
function parseCron(cron) {
|
|
209
|
+
const fields = cron.split(" ");
|
|
210
|
+
const [minutes, hours, days, months, weekdays] = fields.map((field, index) => cronField(field, cronBounds[index] ?? [0, 0]));
|
|
211
|
+
if (fields.length !== 5 || !minutes || !hours || !days || !months || !weekdays)
|
|
212
|
+
return;
|
|
213
|
+
return {
|
|
214
|
+
minutes,
|
|
215
|
+
hours,
|
|
216
|
+
days,
|
|
217
|
+
months,
|
|
218
|
+
weekdays: new Set([...weekdays].map((value) => value % 7)),
|
|
219
|
+
dayRestricted: !(fields[2] ?? "").startsWith("*"),
|
|
220
|
+
weekdayRestricted: !(fields[4] ?? "").startsWith("*")
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
function isScheduleRule(value) {
|
|
224
|
+
return guard(ScheduleRule)(value) && (!("cron" in value) || parseCron(value.cron) !== undefined);
|
|
225
|
+
}
|
|
226
|
+
var ScheduleVersion = Struct({
|
|
227
|
+
contractVersion: Literal("schedule.v1"),
|
|
228
|
+
id: String4.check(isMinLength(1)),
|
|
229
|
+
scheduleId: String4.check(isMinLength(1)),
|
|
230
|
+
workspaceId: String4.check(isMinLength(1)),
|
|
231
|
+
teamId: optionalKey(String4.check(isMinLength(1))),
|
|
232
|
+
loopId: optionalKey(String4.check(isMinLength(1))),
|
|
233
|
+
name: optionalKey(String4.check(isMinLength(1), isMaxLength(200))),
|
|
234
|
+
version: Int.check(isGreaterThanOrEqualTo(1)),
|
|
235
|
+
status: Literals(ScheduleVersionStatuses),
|
|
236
|
+
timezone: String4.check(isMinLength(1), isMaxLength(80)),
|
|
237
|
+
rule: ScheduleRule,
|
|
238
|
+
misfirePolicy: Literals(ScheduleMisfirePolicies),
|
|
239
|
+
overlapPolicy: Literals(ScheduleOverlapPolicies),
|
|
240
|
+
maxCatchUp: Int.check(isGreaterThanOrEqualTo(0), isLessThanOrEqualTo(200)),
|
|
241
|
+
misfireGraceSeconds: optionalKey(Int.check(isGreaterThanOrEqualTo(0), isLessThanOrEqualTo(604800))),
|
|
242
|
+
inputSchemaRef: optionalKey(LoopDataSchemaRef),
|
|
243
|
+
input: optionalKey(SafeJson),
|
|
244
|
+
createdAt: String4.check(isMinLength(1))
|
|
245
|
+
});
|
|
246
|
+
var zones = new Map;
|
|
247
|
+
var resolvedLocalDateTimes = new Map;
|
|
248
|
+
|
|
249
|
+
// packages/core/src/kit-declarations.ts
|
|
250
|
+
var LoopCapabilities = [
|
|
251
|
+
"agent_work",
|
|
252
|
+
"ask",
|
|
253
|
+
"call",
|
|
254
|
+
"verify",
|
|
255
|
+
"change_request",
|
|
256
|
+
"write_back",
|
|
257
|
+
"post_comment",
|
|
258
|
+
"create_tasks",
|
|
259
|
+
"merge_change_request",
|
|
260
|
+
"approve_change_request",
|
|
261
|
+
"publish_release",
|
|
262
|
+
"read_transcripts",
|
|
263
|
+
"read_change_request",
|
|
264
|
+
"measure",
|
|
265
|
+
"claim",
|
|
266
|
+
"propose",
|
|
267
|
+
"read_project",
|
|
268
|
+
"draft_update"
|
|
269
|
+
];
|
|
270
|
+
var JsonObject = Record(String4, Json);
|
|
271
|
+
var SecretName = String4.check(isPattern(/^[A-Za-z_][A-Za-z0-9_]{0,127}$/));
|
|
272
|
+
var EventFilterValue = Union([String4, Finite, Boolean2, Null]);
|
|
273
|
+
var LoopManifest = Struct({
|
|
274
|
+
id: String4,
|
|
275
|
+
title: String4,
|
|
276
|
+
version: optionalKey(LoopVersion),
|
|
277
|
+
input: JsonObject,
|
|
278
|
+
output: JsonObject,
|
|
279
|
+
outcome: optionalKey(Literals(["feature", "bug", "refactor", "investigation", "docs", "migration", "performance"])),
|
|
280
|
+
agents: Record(String4, String4),
|
|
281
|
+
checkout: Literals(["none", "read", "write"]),
|
|
282
|
+
when: ArraySchema(Struct({
|
|
283
|
+
event: String4,
|
|
284
|
+
filter: optionalKey(Record(String4, Union([EventFilterValue, ArraySchema(EventFilterValue)]))),
|
|
285
|
+
input: Record(String4, String4),
|
|
286
|
+
values: optionalKey(JsonObject)
|
|
287
|
+
})),
|
|
288
|
+
offers: ArraySchema(Struct({
|
|
289
|
+
id: String4,
|
|
290
|
+
title: String4,
|
|
291
|
+
loop: String4,
|
|
292
|
+
from: optionalKey(String4)
|
|
293
|
+
})),
|
|
294
|
+
capabilities: ArraySchema(Literals(LoopCapabilities)),
|
|
295
|
+
secrets: optionalKey(ArraySchema(SecretName)),
|
|
296
|
+
network: optionalKey(AgentSandboxNetwork),
|
|
297
|
+
schedule: optionalKey(Struct({ rule: ScheduleRule, timezone: String4 }))
|
|
298
|
+
});
|
|
299
|
+
var LoopDetail = Struct({
|
|
300
|
+
id: String4,
|
|
301
|
+
resolved: optionalKey(Struct({
|
|
302
|
+
...ProgramLoop.fields,
|
|
303
|
+
agents: LoopManifest.fields.agents,
|
|
304
|
+
when: LoopManifest.fields.when,
|
|
305
|
+
schedule: optionalKey(Struct({
|
|
306
|
+
rule: ScheduleRule,
|
|
307
|
+
timezone: String4,
|
|
308
|
+
on: Boolean2,
|
|
309
|
+
nextRunAt: optionalKey(String4)
|
|
310
|
+
}))
|
|
311
|
+
}))
|
|
312
|
+
});
|
|
313
|
+
var AgentDeclaration = Struct({
|
|
314
|
+
extends: optionalKey(String4),
|
|
315
|
+
instructions: optionalKey(String4),
|
|
316
|
+
harness: optionalKey(String4),
|
|
317
|
+
model: optionalKey(String4),
|
|
318
|
+
effort: optionalKey(Literals(AgentEfforts)),
|
|
319
|
+
fallbacks: optionalKey(ArraySchema(AgentFallback)),
|
|
320
|
+
tools: optionalKey(ArraySchema(Literals(AgentCapabilities))),
|
|
321
|
+
skills: optionalKey(ArraySchema(String4.check(isMinLength(1)))),
|
|
322
|
+
network: optionalKey(Union([Struct({ hosts: ArraySchema(String4) }), Literal("open")])),
|
|
323
|
+
sandbox: optionalKey(Literal("docker"))
|
|
324
|
+
});
|
|
325
|
+
var scheduleFields = {
|
|
326
|
+
name: String4.check(isMinLength(1)),
|
|
327
|
+
loop: String4,
|
|
328
|
+
team: optionalKey(String4),
|
|
329
|
+
input: optionalKey(JsonObject),
|
|
330
|
+
timezone: String4,
|
|
331
|
+
misfire: optionalKey(Literals(ScheduleMisfirePolicies)),
|
|
332
|
+
overlap: optionalKey(Literals(ScheduleOverlapPolicies))
|
|
333
|
+
};
|
|
334
|
+
var ScheduleDeclaration = Union([
|
|
335
|
+
Struct({
|
|
336
|
+
...scheduleFields,
|
|
337
|
+
cron: String4.check(makeFilter((cron) => isScheduleRule({ cron }) || "five cron fields, each within its range"))
|
|
338
|
+
}),
|
|
339
|
+
Struct({
|
|
340
|
+
...scheduleFields,
|
|
341
|
+
rule: declare((value) => isScheduleRule(value), {
|
|
342
|
+
expected: "a Schedule rule: frequency daily or weekly, hour, minute, and optionally second and daysOfWeek"
|
|
343
|
+
})
|
|
344
|
+
})
|
|
345
|
+
]);
|
|
346
|
+
var CarriedKit = Struct({
|
|
347
|
+
name: KitName,
|
|
348
|
+
version: String4.check(isMinLength(1)),
|
|
349
|
+
setup: KitDigest,
|
|
350
|
+
loops: ArraySchema(String4),
|
|
351
|
+
agents: ArraySchema(String4)
|
|
352
|
+
});
|
|
353
|
+
var KitDeclarations = Struct({
|
|
354
|
+
loops: ArraySchema(LoopManifest),
|
|
355
|
+
agents: Record(String4, AgentDeclaration),
|
|
356
|
+
schedules: optionalKey(Record(String4, ScheduleDeclaration)),
|
|
357
|
+
carried: optionalKey(ArraySchema(CarriedKit))
|
|
358
|
+
});
|
|
359
|
+
var sameLoop = toEquivalence(LoopManifest);
|
|
360
|
+
var sameAgent = toEquivalence(AgentDeclaration);
|
|
361
|
+
|
|
362
|
+
// packages/sdk/src/loop/define.ts
|
|
363
|
+
var LoopOutcome = Literals([
|
|
364
|
+
"feature",
|
|
365
|
+
"bug",
|
|
366
|
+
"refactor",
|
|
367
|
+
"investigation",
|
|
368
|
+
"docs",
|
|
369
|
+
"migration",
|
|
370
|
+
"performance"
|
|
371
|
+
]);
|
|
372
|
+
var defineLoop = (definition) => definition;
|
|
373
|
+
|
|
374
|
+
class ManifestInvalid extends TaggedError2()("ManifestInvalid", {
|
|
375
|
+
loop: String4,
|
|
376
|
+
message: String4
|
|
377
|
+
}) {
|
|
378
|
+
}
|
|
379
|
+
var jsonSchemaOf = (loop, schema) => try_2({
|
|
380
|
+
try: () => toJsonSchemaDocument(schema),
|
|
381
|
+
catch: (error) => new ManifestInvalid({ loop, message: `Schema has no JSON Schema: ${String(error)}` })
|
|
382
|
+
}).pipe(flatMap3((document) => decodeUnknownEffect2(JsonObjectSchema)({ ...document.schema, $defs: document.definitions }).pipe(mapError2((error) => new ManifestInvalid({ loop, message: error.message })))));
|
|
383
|
+
var JsonObjectSchema = Record(String4, Json);
|
|
384
|
+
// node_modules/.bun/effect@4.1.2/node_modules/effect/dist/workflow/internal/crypto.js
|
|
385
|
+
var encoder = /* @__PURE__ */ new TextEncoder;
|
|
386
|
+
var makeHashDigest = (original) => WebCrypto.use((crypto) => map8(webCryptoDigest(crypto, sha256, encoder.encode(original)), (bytes) => encode(bytes).slice(0, 32)));
|
|
387
|
+
|
|
388
|
+
// node_modules/.bun/effect@4.1.2/node_modules/effect/dist/workflow/Workflow.js
|
|
389
|
+
var TypeId = "~effect/workflow/Workflow";
|
|
390
|
+
var EngineTag = /* @__PURE__ */ Service2("effect/workflow/WorkflowEngine");
|
|
391
|
+
var InstanceTag = /* @__PURE__ */ Service2("effect/workflow/WorkflowEngine/WorkflowInstance");
|
|
392
|
+
var makeExecutionIdFromPayload = (self, payload) => makeHashDigest(`${self._tag.length}:${self._tag}:${self.idempotencyKey(payload)}`);
|
|
393
|
+
var Proto = {
|
|
394
|
+
[TypeId]: TypeId,
|
|
395
|
+
annotate(tag, value) {
|
|
396
|
+
return makeProto({
|
|
397
|
+
_tag: this._tag,
|
|
398
|
+
payloadSchema: this.payloadSchema,
|
|
399
|
+
successSchema: this.successSchema,
|
|
400
|
+
errorSchema: this.errorSchema,
|
|
401
|
+
annotations: add(this.annotations, tag, value),
|
|
402
|
+
idempotencyKey: this.idempotencyKey,
|
|
403
|
+
suspendedRetrySchedule: this.suspendedRetrySchedule
|
|
404
|
+
});
|
|
405
|
+
},
|
|
406
|
+
annotateMerge(context) {
|
|
407
|
+
return makeProto({
|
|
408
|
+
_tag: this._tag,
|
|
409
|
+
payloadSchema: this.payloadSchema,
|
|
410
|
+
successSchema: this.successSchema,
|
|
411
|
+
errorSchema: this.errorSchema,
|
|
412
|
+
annotations: merge3(this.annotations, context),
|
|
413
|
+
idempotencyKey: this.idempotencyKey,
|
|
414
|
+
suspendedRetrySchedule: this.suspendedRetrySchedule
|
|
415
|
+
});
|
|
416
|
+
},
|
|
417
|
+
execute(fields, opts) {
|
|
418
|
+
return suspend3(() => {
|
|
419
|
+
const payload = this.payloadSchema.make(fields);
|
|
420
|
+
const run = flatMap3(EngineTag, (engine) => flatMap3(makeExecutionIdFromPayload(this, payload), (executionId) => andThen2(annotateCurrentSpan({
|
|
421
|
+
executionId
|
|
422
|
+
}), engine.execute(this, {
|
|
423
|
+
executionId,
|
|
424
|
+
payload,
|
|
425
|
+
discard: opts?.discard,
|
|
426
|
+
detached: opts?.detached,
|
|
427
|
+
suspendedRetrySchedule: this.suspendedRetrySchedule
|
|
428
|
+
}))));
|
|
429
|
+
return opts?.discard ? run : withPendingActivity(run);
|
|
430
|
+
}).pipe(withSpan(`${this._tag}.execute`, {}, {
|
|
431
|
+
captureStackTrace: false
|
|
432
|
+
}));
|
|
433
|
+
},
|
|
434
|
+
poll(executionId) {
|
|
435
|
+
return flatMap3(EngineTag, (engine) => engine.poll(this, executionId)).pipe(withSpan(`${this._tag}.poll`, {
|
|
436
|
+
attributes: {
|
|
437
|
+
executionId
|
|
438
|
+
}
|
|
439
|
+
}, {
|
|
440
|
+
captureStackTrace: false
|
|
441
|
+
}));
|
|
442
|
+
},
|
|
443
|
+
interrupt(executionId) {
|
|
444
|
+
return flatMap3(EngineTag, (engine) => engine.interrupt(this, executionId)).pipe(withSpan(`${this._tag}.interrupt`, {
|
|
445
|
+
attributes: {
|
|
446
|
+
executionId
|
|
447
|
+
}
|
|
448
|
+
}, {
|
|
449
|
+
captureStackTrace: false
|
|
450
|
+
}));
|
|
451
|
+
},
|
|
452
|
+
resume(executionId) {
|
|
453
|
+
return flatMap3(EngineTag, (engine) => engine.resume(this, executionId)).pipe(withSpan(`${this._tag}.resume`, {
|
|
454
|
+
attributes: {
|
|
455
|
+
executionId
|
|
456
|
+
}
|
|
457
|
+
}, {
|
|
458
|
+
captureStackTrace: false
|
|
459
|
+
}));
|
|
460
|
+
},
|
|
461
|
+
toLayer(execute) {
|
|
462
|
+
return effectDiscard(flatMap3(EngineTag, (engine) => engine.register(this, execute)));
|
|
463
|
+
},
|
|
464
|
+
executionId(payload) {
|
|
465
|
+
return flatMap3(orDie(this.payloadSchema.makeEffect(payload)), (payload) => makeExecutionIdFromPayload(this, payload));
|
|
466
|
+
},
|
|
467
|
+
withCompensation: (...args) => withCompensation(...args)
|
|
468
|
+
};
|
|
469
|
+
var makeProto = (options) => {
|
|
470
|
+
function Workflow() {}
|
|
471
|
+
Object.setPrototypeOf(Workflow, Proto);
|
|
472
|
+
Object.assign(Workflow, options);
|
|
473
|
+
return Workflow;
|
|
474
|
+
};
|
|
475
|
+
var make14 = (tag, options) => makeProto({
|
|
476
|
+
_tag: tag,
|
|
477
|
+
payloadSchema: isSchema(options.payload) ? options.payload : Struct(options.payload),
|
|
478
|
+
successSchema: options.success ?? Void,
|
|
479
|
+
errorSchema: options.error ?? Never,
|
|
480
|
+
annotations: options.annotations ?? empty3(),
|
|
481
|
+
idempotencyKey: options.idempotencyKey,
|
|
482
|
+
suspendedRetrySchedule: options.suspendedRetrySchedule
|
|
483
|
+
});
|
|
484
|
+
var ResultTypeId = "~effect/workflow/Workflow/Result";
|
|
485
|
+
var isResult = (u) => hasProperty(u, ResultTypeId);
|
|
486
|
+
class Suspended extends (/* @__PURE__ */ Class2("effect/workflow/Workflow/Suspended")({
|
|
487
|
+
_tag: /* @__PURE__ */ tag("Suspended"),
|
|
488
|
+
cause: /* @__PURE__ */ optional(/* @__PURE__ */ Cause(Never, /* @__PURE__ */ Defect())),
|
|
489
|
+
failed: /* @__PURE__ */ optional(Boolean2)
|
|
490
|
+
})) {
|
|
491
|
+
[ResultTypeId] = ResultTypeId;
|
|
492
|
+
}
|
|
493
|
+
var wrapActivityResult = (effect, isSuspend) => contextWith((context) => {
|
|
494
|
+
const instance = get4(context, InstanceTag);
|
|
495
|
+
return acquireUseRelease(sync2(() => adoptActivityUnsafe(context, instance) ?? registerActivityUnsafe(instance)), () => effect, (registration, exit) => {
|
|
496
|
+
releaseActivityUnsafe(registration);
|
|
497
|
+
const isSuspended = isSuccess2(exit) && isSuspend(exit.value);
|
|
498
|
+
if (isSuccess2(exit) && isResult(exit.value) && exit.value._tag === "Suspended" && exit.value.cause) {
|
|
499
|
+
instance.cause = instance.cause ? combine2(instance.cause, exit.value.cause) : exit.value.cause;
|
|
500
|
+
}
|
|
501
|
+
return isSuspended && instance.activityState.count > 0 ? waitForZero(instance) : void_3;
|
|
502
|
+
});
|
|
503
|
+
});
|
|
504
|
+
var PendingActivityRegistration = /* @__PURE__ */ Service2("effect/workflow/Workflow/PendingActivityRegistration");
|
|
505
|
+
var registerActivityUnsafe = (instance) => {
|
|
506
|
+
const state = instance.activityState;
|
|
507
|
+
if (state.count === 0)
|
|
508
|
+
state.latch.closeUnsafe();
|
|
509
|
+
state.count++;
|
|
510
|
+
return {
|
|
511
|
+
instance,
|
|
512
|
+
state: "pending"
|
|
513
|
+
};
|
|
514
|
+
};
|
|
515
|
+
var adoptActivityUnsafe = (context, instance) => {
|
|
516
|
+
const pending = getOrUndefined2(context, PendingActivityRegistration);
|
|
517
|
+
if (!pending || pending.instance !== instance) {
|
|
518
|
+
return;
|
|
519
|
+
}
|
|
520
|
+
if (pending.state !== "pending") {
|
|
521
|
+
throw new Error("Workflow.wrapActivityResult: pending child registration has already been consumed");
|
|
522
|
+
}
|
|
523
|
+
pending.state = "adopted";
|
|
524
|
+
return pending;
|
|
525
|
+
};
|
|
526
|
+
var releaseActivityUnsafe = (registration) => {
|
|
527
|
+
if (registration.state === "released")
|
|
528
|
+
return;
|
|
529
|
+
registration.state = "released";
|
|
530
|
+
const state = registration.instance.activityState;
|
|
531
|
+
state.count--;
|
|
532
|
+
if (state.count === 0)
|
|
533
|
+
state.latch.openUnsafe();
|
|
534
|
+
};
|
|
535
|
+
var withPendingActivity = (effect) => contextWith((context) => {
|
|
536
|
+
const instance = getOrUndefined2(context, InstanceTag);
|
|
537
|
+
if (!instance)
|
|
538
|
+
return effect;
|
|
539
|
+
return acquireUseRelease(sync2(() => registerActivityUnsafe(instance)), (registration) => provideService(effect, PendingActivityRegistration, registration), (registration) => sync2(() => releaseActivityUnsafe(registration)));
|
|
540
|
+
});
|
|
541
|
+
var waitForZero = /* @__PURE__ */ fnUntraced(function* (instance) {
|
|
542
|
+
const state = instance.activityState;
|
|
543
|
+
while (true) {
|
|
544
|
+
if (state.count > 0) {
|
|
545
|
+
yield* state.latch.await;
|
|
546
|
+
yield* yieldNow;
|
|
547
|
+
continue;
|
|
548
|
+
}
|
|
549
|
+
yield* yieldNow;
|
|
550
|
+
if (state.count === 0)
|
|
551
|
+
return;
|
|
552
|
+
}
|
|
553
|
+
});
|
|
554
|
+
var addFinalizer = /* @__PURE__ */ fnUntraced(function* (f) {
|
|
555
|
+
const instance = yield* InstanceTag;
|
|
556
|
+
const services = yield* context();
|
|
557
|
+
yield* addFinalizerExit(instance.scope, (exit) => instance.abandoned ? void_3 : provideContext2(f(exit), services));
|
|
558
|
+
});
|
|
559
|
+
var withCompensation = /* @__PURE__ */ dual(2, (effect, compensation) => uninterruptibleMask2((restore) => tap2(restore(effect), (value) => addFinalizer((exit) => isSuccess2(exit) ? void_3 : compensation(value, exit.cause)))));
|
|
560
|
+
var suspend = (instance) => interruptible(callback3(() => {
|
|
561
|
+
instance.suspended = true;
|
|
562
|
+
const fiber = getCurrent();
|
|
563
|
+
fiber.interruptUnsafe(fiber.id);
|
|
564
|
+
}));
|
|
565
|
+
|
|
566
|
+
// node_modules/.bun/effect@4.1.2/node_modules/effect/dist/workflow/DurableDeferred.js
|
|
567
|
+
var TypeId2 = "~effect/workflow/DurableDeferred";
|
|
568
|
+
var make = (name, options) => {
|
|
569
|
+
const successSchema = options?.success ?? Void;
|
|
570
|
+
const errorSchema = options?.error ?? Never;
|
|
571
|
+
return {
|
|
572
|
+
[TypeId2]: TypeId2,
|
|
573
|
+
name,
|
|
574
|
+
successSchema,
|
|
575
|
+
errorSchema,
|
|
576
|
+
exitSchema: Exit(toCodecJson(successSchema), toCodecJson(errorSchema), toCodecJson(Defect())),
|
|
577
|
+
withActivityAttempt: gen(function* () {
|
|
578
|
+
const attempt = yield* CurrentAttempt;
|
|
579
|
+
return make(`${name}/${attempt}`, {
|
|
580
|
+
success: successSchema,
|
|
581
|
+
error: errorSchema
|
|
582
|
+
});
|
|
583
|
+
})
|
|
584
|
+
};
|
|
585
|
+
};
|
|
586
|
+
var EngineTag2 = /* @__PURE__ */ Service2("effect/workflow/WorkflowEngine");
|
|
587
|
+
var InstanceTag2 = /* @__PURE__ */ Service2("effect/workflow/WorkflowEngine/WorkflowInstance");
|
|
588
|
+
var CurrentAttempt = /* @__PURE__ */ Reference("effect/workflow/Activity/CurrentAttempt", {
|
|
589
|
+
defaultValue: () => 1
|
|
590
|
+
});
|
|
591
|
+
var awaitOwners = /* @__PURE__ */ new WeakMap;
|
|
592
|
+
var registerAwait = (instance, name) => {
|
|
593
|
+
instance.awaitedDeferreds.set(name, (instance.awaitedDeferreds.get(name) ?? 0) + 1);
|
|
594
|
+
awaitOwners.get(instance)?.push(name);
|
|
595
|
+
};
|
|
596
|
+
var await_ = /* @__PURE__ */ fnUntraced(function* (self) {
|
|
597
|
+
const engine = yield* EngineTag2;
|
|
598
|
+
const instance = yield* InstanceTag2;
|
|
599
|
+
registerAwait(instance, self.name);
|
|
600
|
+
const exit = yield* wrapActivityResult(engine.deferredResult(self), isNone);
|
|
601
|
+
if (isNone(exit)) {
|
|
602
|
+
return yield* suspend(instance);
|
|
603
|
+
}
|
|
604
|
+
return yield* exit.value;
|
|
605
|
+
});
|
|
606
|
+
class TokenParsed extends (/* @__PURE__ */ Class2("effect/workflow/DurableDeferred/TokenParsed")({
|
|
607
|
+
workflowName: String4,
|
|
608
|
+
executionId: String4,
|
|
609
|
+
deferredName: String4
|
|
610
|
+
})) {
|
|
611
|
+
get asToken() {
|
|
612
|
+
return encode3(JSON.stringify([this.workflowName, this.executionId, this.deferredName]));
|
|
613
|
+
}
|
|
614
|
+
static FromString = /* @__PURE__ */ String4.pipe(/* @__PURE__ */ decodeTo2(/* @__PURE__ */ fromJsonString(/* @__PURE__ */ Tuple2([String4, String4, String4])), {
|
|
615
|
+
decode: /* @__PURE__ */ decodeBase64UrlString(),
|
|
616
|
+
encode: /* @__PURE__ */ encodeBase64Url()
|
|
617
|
+
}), /* @__PURE__ */ decodeTo2(TokenParsed, {
|
|
618
|
+
decode: /* @__PURE__ */ transform(([workflowName, executionId, deferredName]) => new TokenParsed({
|
|
619
|
+
workflowName,
|
|
620
|
+
executionId,
|
|
621
|
+
deferredName
|
|
622
|
+
})),
|
|
623
|
+
encode: /* @__PURE__ */ transform((parsed) => [parsed.workflowName, parsed.executionId, parsed.deferredName])
|
|
624
|
+
}));
|
|
625
|
+
static fromString = /* @__PURE__ */ decodeSync(TokenParsed.FromString);
|
|
626
|
+
static encode = /* @__PURE__ */ encodeSync(TokenParsed.FromString);
|
|
627
|
+
}
|
|
628
|
+
var token = /* @__PURE__ */ fnUntraced(function* (self) {
|
|
629
|
+
const instance = yield* InstanceTag2;
|
|
630
|
+
return tokenFromExecutionId(self, instance);
|
|
631
|
+
});
|
|
632
|
+
var tokenFromExecutionId = /* @__PURE__ */ dual(2, (self, options) => new TokenParsed({
|
|
633
|
+
workflowName: options.workflow._tag,
|
|
634
|
+
executionId: options.executionId,
|
|
635
|
+
deferredName: self.name
|
|
636
|
+
}).asToken);
|
|
637
|
+
|
|
638
|
+
// node_modules/.bun/effect@4.1.2/node_modules/effect/dist/workflow/Activity.js
|
|
639
|
+
var TypeId3 = "~effect/workflow/Activity";
|
|
640
|
+
var make2 = (options) => {
|
|
641
|
+
const successSchema = options.success ?? Void;
|
|
642
|
+
const errorSchema = options.error ?? Never;
|
|
643
|
+
const successSchemaJson = toCodecJson(successSchema);
|
|
644
|
+
const errorSchemaJson = toCodecJson(errorSchema);
|
|
645
|
+
let execute;
|
|
646
|
+
const executeWithoutInterrupt = retryOnInterrupt(options.name, options.interruptRetryPolicy)(options.execute);
|
|
647
|
+
const self = {
|
|
648
|
+
...Prototype({
|
|
649
|
+
label: "Activity",
|
|
650
|
+
evaluate(_) {
|
|
651
|
+
return execute;
|
|
652
|
+
}
|
|
653
|
+
}),
|
|
654
|
+
[TypeId3]: TypeId3,
|
|
655
|
+
name: options.name,
|
|
656
|
+
successSchema,
|
|
657
|
+
errorSchema,
|
|
658
|
+
exitSchema: Exit(successSchemaJson, errorSchemaJson, Defect()),
|
|
659
|
+
exitSchemaPartial: Exit(successSchemaJson, errorSchemaJson, Unknown),
|
|
660
|
+
annotations: options.annotations ?? empty3(),
|
|
661
|
+
annotate(tag, value) {
|
|
662
|
+
return make2({
|
|
663
|
+
...options,
|
|
664
|
+
annotations: add(self.annotations, tag, value)
|
|
665
|
+
});
|
|
666
|
+
},
|
|
667
|
+
annotateMerge(context) {
|
|
668
|
+
return make2({
|
|
669
|
+
...options,
|
|
670
|
+
annotations: merge3(self.annotations, context)
|
|
671
|
+
});
|
|
672
|
+
},
|
|
673
|
+
execute: executeWithoutInterrupt,
|
|
674
|
+
executeEncoded: matchEffect2(executeWithoutInterrupt, {
|
|
675
|
+
onFailure: (error) => flatMap3(orDie(encodeEffect(errorSchemaJson)(error)), fail7),
|
|
676
|
+
onSuccess: (value) => orDie(encodeEffect(successSchemaJson)(value))
|
|
677
|
+
})
|
|
678
|
+
};
|
|
679
|
+
execute = makeExecute(self);
|
|
680
|
+
return self;
|
|
681
|
+
};
|
|
682
|
+
var interruptRetryPolicy = /* @__PURE__ */ min2([exponential(400, 1.5), spaced("10 seconds")]).pipe(/* @__PURE__ */ setInputType(), /* @__PURE__ */ while_((meta) => meta.attempt <= 10 && hasInterrupts2(meta.input)));
|
|
683
|
+
var retryOnInterrupt = (name, policy = interruptRetryPolicy) => (effect) => flatMap3(InstanceTag3, (instance) => effect.pipe(sandbox, retry({
|
|
684
|
+
schedule: policy,
|
|
685
|
+
while: () => !instance.suspended
|
|
686
|
+
}), catch_((cause) => hasInterrupts2(cause) && !instance.suspended ? die3(`Activity "${name}" interrupted and retry attempts exhausted`) : failCause3(cause))));
|
|
687
|
+
var CurrentAttempt2 = /* @__PURE__ */ Reference("effect/workflow/Activity/CurrentAttempt", {
|
|
688
|
+
defaultValue: () => 1
|
|
689
|
+
});
|
|
690
|
+
var EngineTag3 = /* @__PURE__ */ Service2("effect/workflow/WorkflowEngine");
|
|
691
|
+
var InstanceTag3 = /* @__PURE__ */ Service2("effect/workflow/WorkflowEngine/WorkflowInstance");
|
|
692
|
+
var makeExecute = /* @__PURE__ */ fnUntraced(function* (activity) {
|
|
693
|
+
const engine = yield* EngineTag3;
|
|
694
|
+
const instance = yield* InstanceTag3;
|
|
695
|
+
const attempt = yield* CurrentAttempt2;
|
|
696
|
+
yield* annotateCurrentSpan({
|
|
697
|
+
executionId: instance.executionId
|
|
698
|
+
});
|
|
699
|
+
const result = yield* wrapActivityResult(engine.activityExecute(activity, attempt), (_) => _._tag === "Suspended");
|
|
700
|
+
if (result._tag === "Suspended") {
|
|
701
|
+
if (result.failed)
|
|
702
|
+
instance.failed = true;
|
|
703
|
+
return yield* suspend(instance);
|
|
704
|
+
}
|
|
705
|
+
return yield* result.exit;
|
|
706
|
+
}, (effect, activity) => withSpan(effect, activity.name, {
|
|
707
|
+
captureStackTrace: false
|
|
708
|
+
}));
|
|
709
|
+
// packages/sdk/src/loop/evidence.ts
|
|
710
|
+
var EvidenceCheck = Struct({
|
|
711
|
+
name: String4,
|
|
712
|
+
command: String4,
|
|
713
|
+
status: Literals(["passed", "failed"]),
|
|
714
|
+
preExisting: Boolean2,
|
|
715
|
+
durationMs: Finite,
|
|
716
|
+
evidenceId: String4,
|
|
717
|
+
outputTail: optionalKey(String4),
|
|
718
|
+
suggested: optionalKey(Boolean2)
|
|
719
|
+
});
|
|
720
|
+
var VerifyResult = Struct({
|
|
721
|
+
revision: String4,
|
|
722
|
+
tree: String4,
|
|
723
|
+
passed: Boolean2,
|
|
724
|
+
unchanged: optionalKey(Boolean2),
|
|
725
|
+
checks: ArraySchema(EvidenceCheck)
|
|
726
|
+
});
|
|
727
|
+
var verdict = (reasons) => reasons.length === 0 ? { settled: true } : { settled: false, reasons };
|
|
728
|
+
var missing = (side) => `No verification evidence for the ${side}`;
|
|
729
|
+
var failsOn = (side, name, tree) => `${name} fails on the ${side} tree ${tree}`;
|
|
730
|
+
var allPass = (side, result) => {
|
|
731
|
+
if (result === undefined)
|
|
732
|
+
return [missing(side)];
|
|
733
|
+
if (result.checks.length === 0)
|
|
734
|
+
return [`No approved verification ran on the ${side} tree ${result.tree}`];
|
|
735
|
+
return result.checks.filter((check) => check.status === "failed" && !check.preExisting).map((check) => failsOn(side, check.name, result.tree));
|
|
736
|
+
};
|
|
737
|
+
var checkOn = (side, result, name) => {
|
|
738
|
+
if (result === undefined)
|
|
739
|
+
return { reason: missing(side) };
|
|
740
|
+
if (name === undefined)
|
|
741
|
+
return { reason: `No check was named for the ${side}` };
|
|
742
|
+
const found = result.checks.find((check) => check.name === name);
|
|
743
|
+
return found === undefined ? { reason: `No evidence for ${name} on the ${side} tree ${result.tree}` } : { found };
|
|
744
|
+
};
|
|
745
|
+
var passesOnHead = (head, name) => {
|
|
746
|
+
const { found, reason } = checkOn("head", head, name);
|
|
747
|
+
if (found === undefined)
|
|
748
|
+
return [reason];
|
|
749
|
+
return found.status === "passed" ? [] : [failsOn("head", found.name, head?.tree)];
|
|
750
|
+
};
|
|
751
|
+
var bugReasons = (input) => {
|
|
752
|
+
const base = checkOn("base", input.base, input.reproducing);
|
|
753
|
+
const head = checkOn("head", input.head, input.reproducing);
|
|
754
|
+
return [
|
|
755
|
+
...base.found === undefined ? [base.reason] : base.found.status === "failed" ? [] : [`${base.found.name} does not fail on the base tree ${input.base?.tree}, so the bug is not reproduced`],
|
|
756
|
+
...head.found === undefined ? [head.reason] : head.found.status === "passed" ? [] : [failsOn("head", head.found.name, input.head?.tree)]
|
|
757
|
+
];
|
|
758
|
+
};
|
|
759
|
+
var conclusionReasons = (conclusion) => {
|
|
760
|
+
if (conclusion === undefined || conclusion.text.trim() === "")
|
|
761
|
+
return ["No conclusion was given"];
|
|
762
|
+
return conclusion.sources.length === 0 ? ["The conclusion names no sources"] : [];
|
|
763
|
+
};
|
|
764
|
+
var scopeReasons = (scope) => {
|
|
765
|
+
if (scope === undefined)
|
|
766
|
+
return ["Review has not judged the scope"];
|
|
767
|
+
if (scope.met)
|
|
768
|
+
return [];
|
|
769
|
+
return scope.unmet.length === 0 ? ["Review found the scope unmet"] : scope.unmet.map((item) => `Review found the scope unmet: ${item}`);
|
|
770
|
+
};
|
|
771
|
+
var evidenceGate = (input) => {
|
|
772
|
+
switch (input.outcome) {
|
|
773
|
+
case "feature":
|
|
774
|
+
return verdict([...allPass("head", input.head), ...scopeReasons(input.review)]);
|
|
775
|
+
case "bug":
|
|
776
|
+
return verdict(bugReasons(input));
|
|
777
|
+
case "refactor":
|
|
778
|
+
return verdict([...allPass("base", input.base), ...allPass("head", input.head)]);
|
|
779
|
+
case "investigation":
|
|
780
|
+
return verdict(conclusionReasons(input.conclusion));
|
|
781
|
+
case "docs":
|
|
782
|
+
return verdict((input.documented ?? []).length === 0 ? ["No documented command was named"] : (input.documented ?? []).flatMap((name) => passesOnHead(input.head, name)));
|
|
783
|
+
case "migration":
|
|
784
|
+
return verdict(passesOnHead(input.head, input.rollback));
|
|
785
|
+
case "performance":
|
|
786
|
+
return verdict([
|
|
787
|
+
...input.measurement === undefined ? ["No final measurement against the merge base was kept"] : input.measurement.verdict === "gain" ? [] : [`The final measurement is ${input.measurement.verdict}: ${input.measurement.reason}`],
|
|
788
|
+
...allPass("head", input.head)
|
|
789
|
+
]);
|
|
790
|
+
default:
|
|
791
|
+
return verdict(allPass("head", input.head));
|
|
792
|
+
}
|
|
793
|
+
};
|
|
794
|
+
|
|
795
|
+
// packages/sdk/src/loop/steps.ts
|
|
796
|
+
class StepFailed extends TaggedError2()("StepFailed", {
|
|
797
|
+
step: String4,
|
|
798
|
+
reason: String4
|
|
799
|
+
}) {
|
|
800
|
+
get message() {
|
|
801
|
+
return `Step "${this.step}" failed: ${this.reason}`;
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
class OutputInvalid extends TaggedError2()("OutputInvalid", {
|
|
806
|
+
step: String4,
|
|
807
|
+
message: String4
|
|
808
|
+
}) {
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
class QuestionRefused extends TaggedError2()("QuestionRefused", {
|
|
812
|
+
step: String4,
|
|
813
|
+
answer: String4,
|
|
814
|
+
options: ArraySchema(String4)
|
|
815
|
+
}) {
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
class WaitTimedOut extends TaggedError2()("WaitTimedOut", {
|
|
819
|
+
step: String4,
|
|
820
|
+
event: String4
|
|
821
|
+
}) {
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
class ChangeRequestClosed extends TaggedError2()("ChangeRequestClosed", {
|
|
825
|
+
step: String4,
|
|
826
|
+
merged: Boolean2
|
|
827
|
+
}) {
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
class ChildFailed extends TaggedError2()("ChildFailed", {
|
|
831
|
+
step: String4,
|
|
832
|
+
loop: String4,
|
|
833
|
+
reason: String4
|
|
834
|
+
}) {
|
|
835
|
+
get message() {
|
|
836
|
+
return `Child Run of "${this.loop}" for Step "${this.step}" failed: ${this.reason}`;
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
class CapabilityDenied extends TaggedError2()("CapabilityDenied", {
|
|
841
|
+
step: String4,
|
|
842
|
+
capability: Literals(LoopCapabilities),
|
|
843
|
+
secret: optionalKey(String4)
|
|
844
|
+
}) {
|
|
845
|
+
get message() {
|
|
846
|
+
return this.secret === undefined ? `Step "${this.step}" needs the "${this.capability}" capability, which this Run was not granted` : `Step "${this.step}" names the Secret "${this.secret}", which its Loop does not declare`;
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
class DuplicateStep extends TaggedError2()("DuplicateStep", {
|
|
851
|
+
step: String4
|
|
852
|
+
}) {
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
class InputInvalid extends TaggedError2()("InputInvalid", {
|
|
856
|
+
loop: String4,
|
|
857
|
+
message: String4
|
|
858
|
+
}) {
|
|
859
|
+
}
|
|
860
|
+
var LoopEvent = Struct({ type: String4, payload: Record(String4, Json) });
|
|
861
|
+
|
|
862
|
+
class LoopRun extends Service2()("@kitman-sh/sdk/loop/LoopRun") {
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
class LoopHost extends Service2()("@kitman-sh/sdk/loop/LoopHost") {
|
|
866
|
+
}
|
|
867
|
+
var agentDeferredNamed = (deferredName) => make(deferredName, { success: Json, error: StepFailed });
|
|
868
|
+
var agentWorkDeferred = (step) => agentDeferredNamed(`agent_work/${step}`);
|
|
869
|
+
var syncDeferred = (step) => agentDeferredNamed(`sync/${step}`);
|
|
870
|
+
var answerDeferred = (step) => make(`ask/${step}`, { success: String4, error: StepFailed });
|
|
871
|
+
var childDeferred = (step) => make(`call/${step}`, { success: Json, error: ChildFailed });
|
|
872
|
+
var eventDeferred = (step) => make(`wait_for/${step}`, { success: LoopEvent, error: WaitTimedOut });
|
|
873
|
+
var verifyDeferred = (step) => make(`verify/${step}`, { success: VerifyResult, error: StepFailed });
|
|
874
|
+
var recordStep = (name, kind, exit) => {
|
|
875
|
+
if (isSuccess2(exit))
|
|
876
|
+
return { name, kind, status: "succeeded", result: exit.value };
|
|
877
|
+
if (hasInterruptsOnly(exit.cause))
|
|
878
|
+
return;
|
|
879
|
+
return { name, kind, status: "failed", error: squash(exit.cause) };
|
|
880
|
+
};
|
|
881
|
+
var takeStep = (name, kind, capability, body) => gen(function* () {
|
|
882
|
+
const run = yield* LoopRun;
|
|
883
|
+
if (run.names.has(name))
|
|
884
|
+
return yield* new DuplicateStep({ step: name });
|
|
885
|
+
if (capability !== undefined && !run.granted.has(capability))
|
|
886
|
+
return yield* new CapabilityDenied({ step: name, capability });
|
|
887
|
+
run.names.add(name);
|
|
888
|
+
return yield* body.pipe(onExit((exit) => sync2(() => {
|
|
889
|
+
const record = recordStep(name, kind, exit);
|
|
890
|
+
if (record !== undefined)
|
|
891
|
+
run.steps.push(record);
|
|
892
|
+
})));
|
|
893
|
+
});
|
|
894
|
+
var launch = (deferred, start) => make2({
|
|
895
|
+
name: deferred.name,
|
|
896
|
+
error: StepFailed,
|
|
897
|
+
execute: gen(function* () {
|
|
898
|
+
return yield* start(yield* LoopHost, yield* token(deferred));
|
|
899
|
+
})
|
|
900
|
+
});
|
|
901
|
+
var toJson = (step, schema, value) => encodeUnknownEffect(toCodecJson(schema))(value).pipe(flatMap3(decodeUnknownEffect2(Json)), mapError2((error) => new StepFailed({ step, reason: error.message })));
|
|
902
|
+
var agentWork = (name, options) => agentWorkAs(agentWorkDeferred, name, options);
|
|
903
|
+
var agentWorkAs = (deferredOf, name, options) => takeStep(name, "agent_work", "agent_work", gen(function* () {
|
|
904
|
+
const run = yield* LoopRun;
|
|
905
|
+
const agent = run.agents[options.agent];
|
|
906
|
+
const undeclared = options.secrets?.find((secret) => !run.secrets.has(secret));
|
|
907
|
+
if (undeclared !== undefined)
|
|
908
|
+
return yield* new CapabilityDenied({ step: name, capability: "agent_work", secret: undeclared });
|
|
909
|
+
if (agent === undefined)
|
|
910
|
+
return yield* new StepFailed({ step: name, reason: `Agent role "${options.agent}" is not declared` });
|
|
911
|
+
const deferred = deferredOf(name);
|
|
912
|
+
const output = yield* jsonSchemaOf(run.loop, options.answer ?? options.output).pipe(mapError2((error) => new StepFailed({ step: name, reason: error.message })));
|
|
913
|
+
yield* launch(deferred, (host, token2) => host.startAgentWork({
|
|
914
|
+
step: name,
|
|
915
|
+
deferredName: deferred.name,
|
|
916
|
+
role: options.agent,
|
|
917
|
+
agent,
|
|
918
|
+
prompt: options.prompt,
|
|
919
|
+
...options.skill === undefined ? undefined : { skill: options.skill },
|
|
920
|
+
output,
|
|
921
|
+
...options.secrets === undefined ? undefined : { secrets: options.secrets },
|
|
922
|
+
...options.timeout === undefined ? undefined : { timeoutMillis: toMillis(fromInputUnsafe(options.timeout)) },
|
|
923
|
+
...options.mergeTarget === undefined ? undefined : { mergeTarget: options.mergeTarget },
|
|
924
|
+
token: token2
|
|
925
|
+
}));
|
|
926
|
+
const submitted = yield* await_(deferred);
|
|
927
|
+
return yield* decodeEffect(toCodecJson(options.output))(submitted).pipe(mapError2((error) => new OutputInvalid({ step: name, message: error.message })));
|
|
928
|
+
}));
|
|
929
|
+
var agentWorkOnce = (name, options) => agentWork(name, options).pipe(catchTag("OutputInvalid", (invalid) => agentWork(`${name}:again`, {
|
|
930
|
+
...options,
|
|
931
|
+
prompt: `${options.prompt}
|
|
932
|
+
|
|
933
|
+
Your last Output was refused: ${invalid.message}. Give it again in the right shape.`
|
|
934
|
+
})));
|
|
935
|
+
var ask = (name, question) => takeStep(name, "ask", "ask", gen(function* () {
|
|
936
|
+
const deferred = answerDeferred(name);
|
|
937
|
+
const offered = "options" in question ? splitQuestionOptions(question.options) : undefined;
|
|
938
|
+
const options = offered?.options;
|
|
939
|
+
const recommended = "recommended" in question ? question.recommended : undefined;
|
|
940
|
+
const informationOnly = "informationOnly" in question ? question.informationOnly : undefined;
|
|
941
|
+
const advice = questionAdvice({
|
|
942
|
+
...offered,
|
|
943
|
+
...recommended === undefined ? undefined : { recommended },
|
|
944
|
+
recommendationReason: question.recommendationReason,
|
|
945
|
+
...informationOnly === undefined ? undefined : { informationOnly }
|
|
946
|
+
});
|
|
947
|
+
const refused = recommendationProblem({ ...advice, ...options === undefined ? undefined : { options } });
|
|
948
|
+
if (refused !== undefined)
|
|
949
|
+
return yield* new StepFailed({ step: name, reason: refused });
|
|
950
|
+
const fallback = question.default === undefined ? recommendedDefault(recommended) : question.default ?? undefined;
|
|
951
|
+
if (fallback !== undefined && options !== undefined && !options.includes(fallback))
|
|
952
|
+
return yield* new QuestionRefused({ step: name, answer: fallback, options });
|
|
953
|
+
yield* launch(deferred, (host, token2) => host.putQuestion({
|
|
954
|
+
step: name,
|
|
955
|
+
prompt: question.prompt,
|
|
956
|
+
...options === undefined ? undefined : { options },
|
|
957
|
+
...advice,
|
|
958
|
+
...fallback === undefined ? undefined : { default: fallback },
|
|
959
|
+
...question.timeout === undefined ? undefined : { timeoutMillis: toMillis(fromInputUnsafe(question.timeout)) },
|
|
960
|
+
token: token2
|
|
961
|
+
}));
|
|
962
|
+
const answer = yield* await_(deferred);
|
|
963
|
+
if (options === undefined) {
|
|
964
|
+
return answer;
|
|
965
|
+
}
|
|
966
|
+
const offeredAnswer = options.find((option) => option === answer);
|
|
967
|
+
if (offeredAnswer === undefined)
|
|
968
|
+
return yield* new QuestionRefused({ step: name, answer, options });
|
|
969
|
+
return offeredAnswer;
|
|
970
|
+
}));
|
|
971
|
+
var call = (name, loop, input) => takeStep(name, "call", "call", gen(function* () {
|
|
972
|
+
const deferred = childDeferred(name);
|
|
973
|
+
const encoded = yield* toJson(name, loop.input, input);
|
|
974
|
+
yield* launch(deferred, (host, token2) => host.admitChild({ step: name, loop: loop.id, input: encoded, token: token2 }));
|
|
975
|
+
const result = yield* await_(deferred);
|
|
976
|
+
return yield* decodeEffect(toCodecJson(loop.output))(result).pipe(mapError2((error) => new ChildFailed({ step: name, loop: loop.id, reason: error.message })));
|
|
977
|
+
}));
|
|
978
|
+
var waitFor = (name, wait) => takeStep(name, "wait_for", undefined, gen(function* () {
|
|
979
|
+
const deferred = eventDeferred(name);
|
|
980
|
+
const timeoutMillis = toMillis(fromInputUnsafe(wait.timeout));
|
|
981
|
+
yield* launch(deferred, (host, token2) => host.awaitEvent({
|
|
982
|
+
step: name,
|
|
983
|
+
event: wait.event,
|
|
984
|
+
...wait.filter === undefined ? undefined : { filter: wait.filter },
|
|
985
|
+
...wait.since === undefined ? undefined : { since: wait.since },
|
|
986
|
+
...wait.or === undefined ? undefined : { or: wait.or },
|
|
987
|
+
timeoutMillis,
|
|
988
|
+
token: token2
|
|
989
|
+
}));
|
|
990
|
+
const event = yield* await_(deferred);
|
|
991
|
+
if (event.type === "change_request.closed" && wait.event !== event.type && wait.or?.some((other) => other.event === event.type) !== true)
|
|
992
|
+
return yield* new ChangeRequestClosed({
|
|
993
|
+
step: name,
|
|
994
|
+
merged: event.payload.merged === true
|
|
995
|
+
});
|
|
996
|
+
return event;
|
|
997
|
+
}));
|
|
998
|
+
var verify = (name, request) => takeStep(name, "verify", "verify", gen(function* () {
|
|
999
|
+
const deferred = verifyDeferred(name);
|
|
1000
|
+
yield* launch(deferred, (host, token2) => host.startVerification({
|
|
1001
|
+
step: name,
|
|
1002
|
+
...request.revision === undefined ? undefined : { revision: request.revision },
|
|
1003
|
+
...request.checks === undefined ? undefined : { checks: request.checks },
|
|
1004
|
+
...request.suggested === undefined || request.suggested.length === 0 ? undefined : { suggested: request.suggested },
|
|
1005
|
+
token: token2
|
|
1006
|
+
}));
|
|
1007
|
+
return yield* await_(deferred);
|
|
1008
|
+
}));
|
|
1009
|
+
// packages/sdk/src/loop/plan.ts
|
|
1010
|
+
var PlanTicket = Struct({
|
|
1011
|
+
key: String4,
|
|
1012
|
+
title: String4,
|
|
1013
|
+
body: String4,
|
|
1014
|
+
acceptanceCriteria: ArraySchema(String4),
|
|
1015
|
+
repoBindingId: optional(String4),
|
|
1016
|
+
blockedBy: ArraySchema(String4),
|
|
1017
|
+
outcome: optional(LoopOutcome)
|
|
1018
|
+
});
|
|
1019
|
+
var cycleMessage = (keys) => `These tickets block each other in a cycle, so none can start: ${keys.join(", ")}`;
|
|
1020
|
+
var ticketsProblem = (tickets) => {
|
|
1021
|
+
const keys = new Set;
|
|
1022
|
+
for (const ticket of tickets) {
|
|
1023
|
+
if (keys.has(ticket.key))
|
|
1024
|
+
return `Two tickets have the key "${ticket.key}"`;
|
|
1025
|
+
keys.add(ticket.key);
|
|
1026
|
+
}
|
|
1027
|
+
for (const ticket of tickets)
|
|
1028
|
+
for (const blocker of ticket.blockedBy)
|
|
1029
|
+
if (!keys.has(blocker))
|
|
1030
|
+
return `Ticket "${ticket.key}" is blocked by "${blocker}", which is not a ticket`;
|
|
1031
|
+
const { blocked } = wavesOf(tickets);
|
|
1032
|
+
return blocked.length === 0 ? undefined : cycleMessage(blocked);
|
|
1033
|
+
};
|
|
1034
|
+
var PlanTickets = ArraySchema(PlanTicket).check(makeFilter((tickets) => ticketsProblem(tickets) ?? true));
|
|
1035
|
+
|
|
1036
|
+
class BlockingCycle extends TaggedError2()("BlockingCycle", {
|
|
1037
|
+
tickets: ArraySchema(String4)
|
|
1038
|
+
}) {
|
|
1039
|
+
get message() {
|
|
1040
|
+
return cycleMessage(this.tickets);
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
var byRepoBinding = (left, right) => (left.repoBindingId ?? "").localeCompare(right.repoBindingId ?? "");
|
|
1044
|
+
function wavesOf(tickets) {
|
|
1045
|
+
const placed = new Set;
|
|
1046
|
+
const waves = [];
|
|
1047
|
+
let left = tickets;
|
|
1048
|
+
while (left.length > 0) {
|
|
1049
|
+
const ready = left.filter((ticket) => ticket.blockedBy.every((blocker) => placed.has(blocker)));
|
|
1050
|
+
if (ready.length === 0)
|
|
1051
|
+
break;
|
|
1052
|
+
for (const ticket of ready)
|
|
1053
|
+
placed.add(ticket.key);
|
|
1054
|
+
waves.push(ready.toSorted(byRepoBinding));
|
|
1055
|
+
left = left.filter((ticket) => !placed.has(ticket.key));
|
|
1056
|
+
}
|
|
1057
|
+
return { waves, blocked: left.map((ticket) => ticket.key) };
|
|
1058
|
+
}
|
|
1059
|
+
var planWaves = (tickets) => suspend3(() => {
|
|
1060
|
+
const { waves, blocked } = wavesOf(tickets);
|
|
1061
|
+
return blocked.length === 0 ? succeed6(waves) : fail7(new BlockingCycle({ tickets: blocked }));
|
|
1062
|
+
});
|
|
1063
|
+
|
|
1064
|
+
// packages/sdk/src/loop/activities.ts
|
|
1065
|
+
var ChangeRequestRequest = Struct({
|
|
1066
|
+
title: String4,
|
|
1067
|
+
body: String4,
|
|
1068
|
+
integration: optional(String4)
|
|
1069
|
+
});
|
|
1070
|
+
var ChangeRequestResult = Struct({ id: String4, number: String4, url: String4 });
|
|
1071
|
+
var WriteBackMilestones = ["started", "change_request_opened", "merged", "failed"];
|
|
1072
|
+
var WriteBackRequest = Struct({
|
|
1073
|
+
milestone: optional(Literals(WriteBackMilestones)),
|
|
1074
|
+
changeRequestUrl: optional(String4)
|
|
1075
|
+
});
|
|
1076
|
+
var RunFile = Struct({ runFile: String4 }).pipe(decodeTo2(Struct({ id: String4 }), transform2({
|
|
1077
|
+
decode: ({ runFile }) => ({ id: runFile }),
|
|
1078
|
+
encode: ({ id }) => ({ runFile: id })
|
|
1079
|
+
})));
|
|
1080
|
+
var FileRequest = Struct({ path: String4, caption: optional(String4) });
|
|
1081
|
+
var ArtifactRequest = Struct({
|
|
1082
|
+
kind: String4,
|
|
1083
|
+
title: String4,
|
|
1084
|
+
text: String4,
|
|
1085
|
+
data: optional(Json),
|
|
1086
|
+
files: optional(ArraySchema(RunFile))
|
|
1087
|
+
});
|
|
1088
|
+
var ArtifactResult = Struct({ artifactId: String4 });
|
|
1089
|
+
var NoteRequest = Struct({ text: String4, artifactId: optional(String4) });
|
|
1090
|
+
var CreateTasksRequest = Struct({
|
|
1091
|
+
tickets: ArraySchema(PlanTicket),
|
|
1092
|
+
projectId: optionalKey(String4)
|
|
1093
|
+
});
|
|
1094
|
+
var CreateTasksResult = Struct({
|
|
1095
|
+
tasks: ArraySchema(Struct({ key: String4, taskId: String4 }))
|
|
1096
|
+
});
|
|
1097
|
+
var AlertTaskRequest = Struct({
|
|
1098
|
+
fingerprint: String4.check(isMinLength(1), isMaxLength(400)),
|
|
1099
|
+
title: String4,
|
|
1100
|
+
windowHours: Int.check(isGreaterThanOrEqualTo(0), isLessThanOrEqualTo(720)),
|
|
1101
|
+
resolved: optionalKey(Boolean2),
|
|
1102
|
+
priority: optionalKey(Literals(["urgent", "high", "medium", "low"]))
|
|
1103
|
+
});
|
|
1104
|
+
var AlertTaskResult = Struct({
|
|
1105
|
+
taskId: optionalKey(String4),
|
|
1106
|
+
created: Boolean2,
|
|
1107
|
+
resolved: optionalKey(Boolean2),
|
|
1108
|
+
joined: optionalKey(Struct({ kind: Literals(["run", "recent"]), runId: String4 }))
|
|
1109
|
+
});
|
|
1110
|
+
var IntegrationBranchRequest = Struct({ repoBindingId: optional(String4) });
|
|
1111
|
+
var IntegrationBranch = Struct({
|
|
1112
|
+
repoBindingId: String4,
|
|
1113
|
+
branch: String4,
|
|
1114
|
+
revision: String4
|
|
1115
|
+
});
|
|
1116
|
+
var MergeChangeRequestRequest = Struct({
|
|
1117
|
+
changeRequestId: String4,
|
|
1118
|
+
head: optionalKey(String4)
|
|
1119
|
+
});
|
|
1120
|
+
var MergeResult = Union([
|
|
1121
|
+
Struct({ status: Literal("merged"), revision: String4 }),
|
|
1122
|
+
Struct({ status: Literal("conflict") }),
|
|
1123
|
+
Struct({ status: Literal("moved"), head: String4 })
|
|
1124
|
+
]);
|
|
1125
|
+
var ApproveChangeRequestRequest = Struct({
|
|
1126
|
+
changeRequestId: String4,
|
|
1127
|
+
head: String4,
|
|
1128
|
+
summary: String4,
|
|
1129
|
+
review: optionalKey(String4),
|
|
1130
|
+
carries: optionalKey(String4)
|
|
1131
|
+
});
|
|
1132
|
+
var ApproveChangeRequestResult = Union([
|
|
1133
|
+
Struct({ approved: Literal(true), reviewId: String4 }),
|
|
1134
|
+
Struct({ approved: Literal(false), reason: String4 })
|
|
1135
|
+
]);
|
|
1136
|
+
var CloseChangeRequestRequest = Struct({
|
|
1137
|
+
number: String4,
|
|
1138
|
+
head: String4,
|
|
1139
|
+
note: String4
|
|
1140
|
+
});
|
|
1141
|
+
var CloseChangeRequestResult = Struct({
|
|
1142
|
+
closed: Boolean2,
|
|
1143
|
+
head: optionalKey(String4)
|
|
1144
|
+
});
|
|
1145
|
+
var RerunPipelineRequest = Union([
|
|
1146
|
+
Struct({ changeRequestId: String4 }),
|
|
1147
|
+
Struct({ ref: String4, all: optionalKey(Boolean2) })
|
|
1148
|
+
]);
|
|
1149
|
+
var RerunPipelineResult = Struct({ head: String4, pipelines: Int });
|
|
1150
|
+
var ReportPipelineRequest = Struct({ changeRequestId: String4, verification: String4 });
|
|
1151
|
+
var ReportPipelineResult = Struct({
|
|
1152
|
+
head: String4,
|
|
1153
|
+
status: Literals(["success", "failed"])
|
|
1154
|
+
});
|
|
1155
|
+
var CommentRequest = Struct({
|
|
1156
|
+
changeRequestId: String4,
|
|
1157
|
+
body: String4,
|
|
1158
|
+
threadId: optionalKey(String4),
|
|
1159
|
+
summary: optionalKey(String4),
|
|
1160
|
+
anchors: optionalKey(ArraySchema(Struct({
|
|
1161
|
+
file: String4,
|
|
1162
|
+
line: Int.check(isGreaterThanOrEqualTo(1)),
|
|
1163
|
+
body: String4.check(isMinLength(1))
|
|
1164
|
+
})))
|
|
1165
|
+
});
|
|
1166
|
+
var ReleaseRequest = Struct({
|
|
1167
|
+
tag: String4,
|
|
1168
|
+
revision: optional(String4),
|
|
1169
|
+
title: String4,
|
|
1170
|
+
notes: String4
|
|
1171
|
+
});
|
|
1172
|
+
var ReleaseResult = Struct({ tag: String4, revision: String4, url: String4 });
|
|
1173
|
+
var ChangeRequestReadRequest = Struct({ changeRequestId: String4 });
|
|
1174
|
+
var PipelineJob = Struct({
|
|
1175
|
+
name: String4,
|
|
1176
|
+
status: Literals(["running", "success", "failed", "skipped"]),
|
|
1177
|
+
url: optional(String4),
|
|
1178
|
+
logTail: optional(String4)
|
|
1179
|
+
});
|
|
1180
|
+
var PipelineStatus = Struct({
|
|
1181
|
+
head: String4,
|
|
1182
|
+
status: Literals(["none", "running", "success", "failed", "canceled"]),
|
|
1183
|
+
source: Literals(["forge", "reported"]),
|
|
1184
|
+
jobs: ArraySchema(PipelineJob),
|
|
1185
|
+
readAt: optionalKey(String4),
|
|
1186
|
+
runnerChecks: optionalKey(ArraySchema(String4))
|
|
1187
|
+
});
|
|
1188
|
+
var ReviewThread = Struct({
|
|
1189
|
+
id: String4,
|
|
1190
|
+
path: optional(String4),
|
|
1191
|
+
line: optional(Int),
|
|
1192
|
+
outdated: optional(Boolean2),
|
|
1193
|
+
comments: ArraySchema(Struct({ author: optional(String4), body: String4 }))
|
|
1194
|
+
});
|
|
1195
|
+
var ReviewThreads = Struct({ threads: ArraySchema(ReviewThread) });
|
|
1196
|
+
var OpenChangeRequestsRequest = Struct({ authors: NonEmptyArray(String4) });
|
|
1197
|
+
var OpenChangeRequest = Struct({
|
|
1198
|
+
number: String4,
|
|
1199
|
+
title: String4,
|
|
1200
|
+
body: String4,
|
|
1201
|
+
url: String4,
|
|
1202
|
+
author: String4,
|
|
1203
|
+
sourceBranch: String4,
|
|
1204
|
+
head: String4
|
|
1205
|
+
});
|
|
1206
|
+
var OpenChangeRequests = Struct({ changeRequests: ArraySchema(OpenChangeRequest) });
|
|
1207
|
+
var OwnChangeRequest = Struct({
|
|
1208
|
+
id: String4,
|
|
1209
|
+
number: String4,
|
|
1210
|
+
url: String4,
|
|
1211
|
+
title: String4,
|
|
1212
|
+
sourceBranch: String4,
|
|
1213
|
+
body: String4
|
|
1214
|
+
});
|
|
1215
|
+
var OwnChangeRequests = Struct({ changeRequests: ArraySchema(OwnChangeRequest) });
|
|
1216
|
+
var TranscriptPoint = Struct({
|
|
1217
|
+
runId: String4,
|
|
1218
|
+
stepAttemptId: String4,
|
|
1219
|
+
sequence: Int
|
|
1220
|
+
});
|
|
1221
|
+
var TranscriptsRequest = Struct({
|
|
1222
|
+
days: Int.check(isGreaterThanOrEqualTo(1), isLessThanOrEqualTo(31))
|
|
1223
|
+
});
|
|
1224
|
+
var TranscriptsResult = Struct({
|
|
1225
|
+
runs: ArraySchema(Struct({
|
|
1226
|
+
runId: String4,
|
|
1227
|
+
loopId: String4,
|
|
1228
|
+
status: optional(Literals(["completed", "failed", "canceled", "expired"])),
|
|
1229
|
+
teamId: optional(String4),
|
|
1230
|
+
failure: optional(String4),
|
|
1231
|
+
retried: optional(Boolean2),
|
|
1232
|
+
entries: ArraySchema(Struct({ stepAttemptId: String4, sequence: Int, kind: String4, text: String4 }))
|
|
1233
|
+
}))
|
|
1234
|
+
});
|
|
1235
|
+
var Citations = NonEmptyArray(TranscriptPoint);
|
|
1236
|
+
var ProposeRequest = Union([
|
|
1237
|
+
Struct({
|
|
1238
|
+
kind: Literal("memory"),
|
|
1239
|
+
teamId: String4,
|
|
1240
|
+
content: String4,
|
|
1241
|
+
citations: Citations
|
|
1242
|
+
}),
|
|
1243
|
+
Struct({
|
|
1244
|
+
kind: Literal("task"),
|
|
1245
|
+
title: String4,
|
|
1246
|
+
description: String4,
|
|
1247
|
+
teamId: optional(String4),
|
|
1248
|
+
key: optionalKey(String4.check(isPattern(/^[a-z0-9]+(?:-[a-z0-9]+)*$/), isMaxLength(80))),
|
|
1249
|
+
citations: Citations
|
|
1250
|
+
})
|
|
1251
|
+
]);
|
|
1252
|
+
var ProposeResult = Struct({
|
|
1253
|
+
kind: Literals(["memory", "task"]),
|
|
1254
|
+
id: String4,
|
|
1255
|
+
matched: optionalKey(Boolean2)
|
|
1256
|
+
});
|
|
1257
|
+
var Health = Literals(["on_track", "at_risk", "off_track"]);
|
|
1258
|
+
var ProjectActivityRequest = Struct({ projectId: String4 });
|
|
1259
|
+
var ProjectActivityResult = Struct({
|
|
1260
|
+
project: Struct({ id: String4, name: String4 }),
|
|
1261
|
+
health: optional(Health),
|
|
1262
|
+
since: optional(String4),
|
|
1263
|
+
runs: ArraySchema(Struct({
|
|
1264
|
+
runId: String4,
|
|
1265
|
+
loopId: String4,
|
|
1266
|
+
status: String4,
|
|
1267
|
+
taskKey: optional(String4),
|
|
1268
|
+
taskTitle: optional(String4),
|
|
1269
|
+
summary: optional(String4),
|
|
1270
|
+
entries: ArraySchema(Struct({ stepAttemptId: String4, sequence: Int, kind: String4, text: String4 }))
|
|
1271
|
+
})),
|
|
1272
|
+
taskChanges: ArraySchema(Struct({ taskKey: String4, title: String4, change: String4, at: String4 }))
|
|
1273
|
+
});
|
|
1274
|
+
var DraftUpdateRequest = Struct({
|
|
1275
|
+
projectId: String4,
|
|
1276
|
+
health: Health,
|
|
1277
|
+
note: String4,
|
|
1278
|
+
writtenFrom: Struct({
|
|
1279
|
+
runs: Int,
|
|
1280
|
+
taskChanges: Int,
|
|
1281
|
+
since: optional(String4)
|
|
1282
|
+
})
|
|
1283
|
+
});
|
|
1284
|
+
var DraftUpdateResult = Struct({ id: String4 });
|
|
1285
|
+
|
|
1286
|
+
class ChangeRequestActivity extends Service2()("@kitman-sh/sdk/loop/ChangeRequestActivity") {
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
class WriteBackActivity extends Service2()("@kitman-sh/sdk/loop/WriteBackActivity") {
|
|
1290
|
+
}
|
|
1291
|
+
|
|
1292
|
+
class ArtifactActivity extends Service2()("@kitman-sh/sdk/loop/ArtifactActivity") {
|
|
1293
|
+
}
|
|
1294
|
+
|
|
1295
|
+
class FileActivity extends Service2()("@kitman-sh/sdk/loop/FileActivity") {
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
class NoteActivity extends Service2()("@kitman-sh/sdk/loop/NoteActivity") {
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1301
|
+
class CommentActivity extends Service2()("@kitman-sh/sdk/loop/CommentActivity") {
|
|
1302
|
+
}
|
|
1303
|
+
|
|
1304
|
+
class CreateTasksActivity extends Service2()("@kitman-sh/sdk/loop/CreateTasksActivity") {
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1307
|
+
class AlertTaskActivity extends Service2()("@kitman-sh/sdk/loop/AlertTaskActivity") {
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
class IntegrationBranchActivity extends Service2()("@kitman-sh/sdk/loop/IntegrationBranchActivity") {
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
class MergeChangeRequestActivity extends Service2()("@kitman-sh/sdk/loop/MergeChangeRequestActivity") {
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
class ReleaseActivity extends Service2()("@kitman-sh/sdk/loop/ReleaseActivity") {
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
class TranscriptsActivity extends Service2()("@kitman-sh/sdk/loop/TranscriptsActivity") {
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
class ProposeActivity extends Service2()("@kitman-sh/sdk/loop/ProposeActivity") {
|
|
1323
|
+
}
|
|
1324
|
+
|
|
1325
|
+
class ProjectActivityActivity extends Service2()("@kitman-sh/sdk/loop/ProjectActivityActivity") {
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1328
|
+
class DraftUpdateActivity extends Service2()("@kitman-sh/sdk/loop/DraftUpdateActivity") {
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1331
|
+
class ChangeRequestReadActivity extends Service2()("@kitman-sh/sdk/loop/ChangeRequestReadActivity") {
|
|
1332
|
+
}
|
|
1333
|
+
var hostActivity = (name, kind, capability, success, execute) => takeStep(name, kind, capability, make2({ name: `${kind}/${name}`, success, error: StepFailed, execute }));
|
|
1334
|
+
var changeRequest = (name, request) => hostActivity(name, "change_request", "change_request", ChangeRequestResult, gen(function* () {
|
|
1335
|
+
return yield* (yield* ChangeRequestActivity).run(request, name);
|
|
1336
|
+
}));
|
|
1337
|
+
var writeBack = (name, request) => hostActivity(name, "write_back", "write_back", Void, gen(function* () {
|
|
1338
|
+
return yield* (yield* WriteBackActivity).run(request, name);
|
|
1339
|
+
}));
|
|
1340
|
+
var artifact = (name, request) => hostActivity(name, "artifact", undefined, ArtifactResult, gen(function* () {
|
|
1341
|
+
return yield* (yield* ArtifactActivity).run(request, name);
|
|
1342
|
+
}));
|
|
1343
|
+
var note = (name, request) => hostActivity(name, "note", undefined, Void, gen(function* () {
|
|
1344
|
+
return yield* (yield* NoteActivity).run(request, name);
|
|
1345
|
+
}));
|
|
1346
|
+
var comment = (name, request) => hostActivity(name, "comment", "post_comment", Void, gen(function* () {
|
|
1347
|
+
return yield* (yield* CommentActivity).run(request, name);
|
|
1348
|
+
}));
|
|
1349
|
+
var createTasks = (name, request) => hostActivity(name, "create_tasks", "create_tasks", CreateTasksResult, gen(function* () {
|
|
1350
|
+
return yield* (yield* CreateTasksActivity).run(request, name);
|
|
1351
|
+
}));
|
|
1352
|
+
var alertTask = (name, request) => hostActivity(name, "create_tasks", "create_tasks", AlertTaskResult, gen(function* () {
|
|
1353
|
+
return yield* (yield* AlertTaskActivity).run(request, name);
|
|
1354
|
+
}));
|
|
1355
|
+
var integrationBranch = (name, request) => hostActivity(name, "integration_branch", "merge_change_request", IntegrationBranch, gen(function* () {
|
|
1356
|
+
return yield* (yield* IntegrationBranchActivity).run(request, name);
|
|
1357
|
+
}));
|
|
1358
|
+
var mergeChangeRequest = (name, request) => hostActivity(name, "merge_change_request", "merge_change_request", MergeResult, gen(function* () {
|
|
1359
|
+
return yield* (yield* MergeChangeRequestActivity).run(request, name);
|
|
1360
|
+
}));
|
|
1361
|
+
var approveChangeRequest = (name, request) => hostActivity(name, "approve_change_request", "approve_change_request", ApproveChangeRequestResult, gen(function* () {
|
|
1362
|
+
return yield* (yield* MergeChangeRequestActivity).approve(request, name);
|
|
1363
|
+
}));
|
|
1364
|
+
var closeChangeRequest = (name, request) => hostActivity(name, "close_change_request", "merge_change_request", CloseChangeRequestResult, gen(function* () {
|
|
1365
|
+
return yield* (yield* MergeChangeRequestActivity).close(request, name);
|
|
1366
|
+
}));
|
|
1367
|
+
var pipelineMoved = (name, changeRequestId, read, timeout = "6 hours") => waitFor(name, {
|
|
1368
|
+
event: "change_request.pipeline",
|
|
1369
|
+
filter: read.readAt === undefined ? { changeRequestId, head: read.head } : { changeRequestId },
|
|
1370
|
+
timeout,
|
|
1371
|
+
...read.readAt === undefined ? undefined : { since: read.readAt }
|
|
1372
|
+
});
|
|
1373
|
+
var rerunPipeline = (name, request) => hostActivity(name, "rerun_pipeline", "merge_change_request", RerunPipelineResult, gen(function* () {
|
|
1374
|
+
return yield* (yield* MergeChangeRequestActivity).rerun(request, name);
|
|
1375
|
+
}));
|
|
1376
|
+
var reportPipeline = (name, request) => hostActivity(name, "report_pipeline", "verify", ReportPipelineResult, gen(function* () {
|
|
1377
|
+
return yield* (yield* MergeChangeRequestActivity).report(request, name);
|
|
1378
|
+
}));
|
|
1379
|
+
var release2 = (name, request) => hostActivity(name, "release", "publish_release", ReleaseResult, gen(function* () {
|
|
1380
|
+
return yield* (yield* ReleaseActivity).run(request, name);
|
|
1381
|
+
}));
|
|
1382
|
+
var transcripts = (name, request) => hostActivity(name, "transcripts", "read_transcripts", TranscriptsResult, gen(function* () {
|
|
1383
|
+
return yield* (yield* TranscriptsActivity).run(request, name);
|
|
1384
|
+
}));
|
|
1385
|
+
var propose = (name, request) => hostActivity(name, "propose", "propose", ProposeResult, gen(function* () {
|
|
1386
|
+
return yield* (yield* ProposeActivity).run(request, name);
|
|
1387
|
+
}));
|
|
1388
|
+
var projectActivity = (name, request) => hostActivity(name, "project_activity", "read_project", ProjectActivityResult, gen(function* () {
|
|
1389
|
+
return yield* (yield* ProjectActivityActivity).run(request, name);
|
|
1390
|
+
}));
|
|
1391
|
+
var pipelineStatus = (name, request) => hostActivity(name, "pipeline_status", "read_change_request", PipelineStatus, gen(function* () {
|
|
1392
|
+
return yield* (yield* ChangeRequestReadActivity).pipeline(request, name);
|
|
1393
|
+
}));
|
|
1394
|
+
var reviewThreads = (name, request) => hostActivity(name, "review_threads", "read_change_request", ReviewThreads, gen(function* () {
|
|
1395
|
+
return yield* (yield* ChangeRequestReadActivity).reviewThreads(request, name);
|
|
1396
|
+
}));
|
|
1397
|
+
var openChangeRequests = (name, request) => hostActivity(name, "open_change_requests", "read_change_request", OpenChangeRequests, gen(function* () {
|
|
1398
|
+
return yield* (yield* ChangeRequestReadActivity).opened(request, name);
|
|
1399
|
+
}));
|
|
1400
|
+
var ownChangeRequests = (name) => hostActivity(name, "own_change_requests", "read_change_request", OwnChangeRequests, gen(function* () {
|
|
1401
|
+
return yield* (yield* ChangeRequestReadActivity).own(name);
|
|
1402
|
+
}));
|
|
1403
|
+
var draftUpdate = (name, request) => hostActivity(name, "draft_update", "draft_update", DraftUpdateResult, gen(function* () {
|
|
1404
|
+
return yield* (yield* DraftUpdateActivity).run(request, name);
|
|
1405
|
+
}));
|
|
1406
|
+
// packages/sdk/src/loop/claims.ts
|
|
1407
|
+
var claimDeferred = (step) => make(`claim/${step}`, { success: ClaimResult, error: StepFailed });
|
|
1408
|
+
var claimOnce = (name, resource, action) => takeStep(name, "claim", "claim", gen(function* () {
|
|
1409
|
+
const deferred = claimDeferred(name);
|
|
1410
|
+
yield* launch(deferred, (host, token) => host.claimResource({ step: name, resource, action, token }));
|
|
1411
|
+
return yield* await_(deferred);
|
|
1412
|
+
}));
|
|
1413
|
+
var takeOver = "Take it over";
|
|
1414
|
+
var holderName = (holder) => holder.private === true ? "a Run of a private Team you are not in" : `Run ${holder.runId} of ${holder.loopId}`;
|
|
1415
|
+
var claim = (name, request) => gen(function* () {
|
|
1416
|
+
const first = yield* claimOnce(name, request.resource, "claim");
|
|
1417
|
+
if (first.status === "granted")
|
|
1418
|
+
return first;
|
|
1419
|
+
const { holder } = first;
|
|
1420
|
+
const fallback = holder.sameLoop ? takeOver : "Leave it";
|
|
1421
|
+
const answer = (yield* LoopRun).granted.has("ask") ? yield* ask(`${name}-offer`, {
|
|
1422
|
+
prompt: `${request.resource} is still held by ${holderName(holder)}${holder.status === undefined ? "" : `, which ${holder.status}`}${holder.reason === undefined ? "" : `: ${holder.reason}`}. Take it over?`,
|
|
1423
|
+
options: [takeOver, "Leave it"],
|
|
1424
|
+
recommended: fallback,
|
|
1425
|
+
recommendationReason: holder.sameLoop ? "The holder is this Loop on the same repository and settled without completing, so nothing else is using it." : "Another Loop holds it and may still need it; waiting is safer than taking it from under that Run.",
|
|
1426
|
+
timeout: request.timeout ?? "10 minutes"
|
|
1427
|
+
}) : fallback;
|
|
1428
|
+
if (answer !== takeOver)
|
|
1429
|
+
return yield* new StepFailed({ step: name, reason: `${request.resource} was left to ${holderName(holder)}` });
|
|
1430
|
+
const taken = yield* claimOnce(`${name}-take-over`, request.resource, "take_over");
|
|
1431
|
+
if (taken.status === "granted")
|
|
1432
|
+
return taken;
|
|
1433
|
+
return yield* new StepFailed({ step: name, reason: `${request.resource} is kept by ${holderName(taken.holder)}` });
|
|
1434
|
+
});
|
|
1435
|
+
|
|
1436
|
+
// packages/sdk/src/loop/measure.ts
|
|
1437
|
+
var MetricStats = Struct({
|
|
1438
|
+
samples: Finite,
|
|
1439
|
+
median: Finite,
|
|
1440
|
+
mean: Finite,
|
|
1441
|
+
min: Finite,
|
|
1442
|
+
max: Finite,
|
|
1443
|
+
stdev: Finite
|
|
1444
|
+
});
|
|
1445
|
+
var MeasureVerdict = Literals(["gain", "no_gain", "guardrail_regressed", "too_noisy"]);
|
|
1446
|
+
var Measurement = Struct({
|
|
1447
|
+
verdict: MeasureVerdict,
|
|
1448
|
+
reason: String4,
|
|
1449
|
+
metrics: ArraySchema(Struct({
|
|
1450
|
+
name: String4,
|
|
1451
|
+
role: Literals(["primary", "guardrail"]),
|
|
1452
|
+
direction: Literals(["lower", "higher"]),
|
|
1453
|
+
base: MetricStats,
|
|
1454
|
+
head: MetricStats,
|
|
1455
|
+
change: Finite,
|
|
1456
|
+
noise: Finite
|
|
1457
|
+
})),
|
|
1458
|
+
suggestion: optional(String4),
|
|
1459
|
+
evidence: MeasureEvidence
|
|
1460
|
+
});
|
|
1461
|
+
var measureDeferred = (step) => make(`measure/${step}`, { success: MeasureEvidence, error: StepFailed });
|
|
1462
|
+
var stats = (values) => {
|
|
1463
|
+
if (values.length === 0)
|
|
1464
|
+
return { samples: 0, median: 0, mean: 0, min: 0, max: 0, stdev: 0 };
|
|
1465
|
+
const sorted = [...values].sort((left, right) => left - right);
|
|
1466
|
+
const middle = Math.floor(sorted.length / 2);
|
|
1467
|
+
const mean = values.reduce((sum, value) => sum + value, 0) / values.length;
|
|
1468
|
+
return {
|
|
1469
|
+
samples: values.length,
|
|
1470
|
+
median: sorted.length % 2 === 0 ? ((sorted[middle - 1] ?? 0) + (sorted[middle] ?? 0)) / 2 : sorted[middle] ?? 0,
|
|
1471
|
+
mean,
|
|
1472
|
+
min: sorted[0] ?? 0,
|
|
1473
|
+
max: sorted.at(-1) ?? 0,
|
|
1474
|
+
stdev: Math.sqrt(values.reduce((sum, value) => sum + (value - mean) ** 2, 0) / values.length)
|
|
1475
|
+
};
|
|
1476
|
+
};
|
|
1477
|
+
var valuesOf = (samples, metric) => samples.flatMap((sample) => sample[metric] === undefined ? [] : [sample[metric]]);
|
|
1478
|
+
var incomplete = (plan, evidence) => plan.metrics.map((metric) => metric.name).filter((metric) => evidence.base.length === 0 || evidence.head.length === 0 || [...evidence.base, ...evidence.head, ...evidence.baseAgain ?? []].some((sample) => sample[metric] === undefined));
|
|
1479
|
+
var relative = (delta, of) => of === 0 ? Math.sign(delta) : delta / Math.abs(of);
|
|
1480
|
+
var noiseFloor = (plan, evidence) => Object.fromEntries(plan.metrics.map((metric) => {
|
|
1481
|
+
const base = stats(valuesOf(evidence.base, metric.name));
|
|
1482
|
+
const again = stats(valuesOf(evidence.baseAgain ?? [], metric.name));
|
|
1483
|
+
const spread = relative(base.stdev, base.median);
|
|
1484
|
+
const gap = again.samples === 0 ? 0 : relative(Math.abs(again.median - base.median), base.median);
|
|
1485
|
+
return [metric.name, Math.max(spread, gap)];
|
|
1486
|
+
}));
|
|
1487
|
+
var judgeMeasurement = (plan, evidence, noise, limits) => {
|
|
1488
|
+
const metrics = plan.metrics.map((metric) => {
|
|
1489
|
+
const base = stats(valuesOf(evidence.base, metric.name));
|
|
1490
|
+
const head = stats(valuesOf(evidence.head, metric.name));
|
|
1491
|
+
const delta = metric.direction === "lower" ? base.median - head.median : head.median - base.median;
|
|
1492
|
+
const change = base.samples === 0 || head.samples === 0 ? 0 : relative(delta, base.median);
|
|
1493
|
+
return { ...metric, base, head, change, noise: noise[metric.name] ?? 0 };
|
|
1494
|
+
});
|
|
1495
|
+
const percent = (fraction) => `${(fraction * 100).toFixed(1)}%`;
|
|
1496
|
+
const primary = metrics.find((metric) => metric.role === "primary");
|
|
1497
|
+
const judged = { metrics, evidence };
|
|
1498
|
+
if (primary === undefined)
|
|
1499
|
+
return { ...judged, verdict: "too_noisy", reason: "The plan names no primary metric" };
|
|
1500
|
+
const missing = incomplete(plan, evidence);
|
|
1501
|
+
if (missing.length > 0)
|
|
1502
|
+
return { ...judged, verdict: "too_noisy", reason: `${missing.join(", ")} is missing from some samples` };
|
|
1503
|
+
if (!Number.isFinite(primary.noise) || primary.noise > limits.threshold) {
|
|
1504
|
+
const steadier = plan.metrics.find((metric) => metric.lowVariance === true && metric.name !== primary.name);
|
|
1505
|
+
return {
|
|
1506
|
+
...judged,
|
|
1507
|
+
verdict: "too_noisy",
|
|
1508
|
+
reason: `${primary.name} strays ${percent(primary.noise)} from itself, more than the ${percent(limits.threshold)} threshold`,
|
|
1509
|
+
suggestion: steadier === undefined ? "Measure a low-variance counter (instructions, allocations, queries) and make it the primary metric" : `Make ${steadier.name}, which varies less, the primary metric`
|
|
1510
|
+
};
|
|
1511
|
+
}
|
|
1512
|
+
const regressed = metrics.filter((metric) => metric.role === "guardrail" && metric.change < -(limits.tolerance + metric.noise));
|
|
1513
|
+
if (regressed.length > 0)
|
|
1514
|
+
return {
|
|
1515
|
+
...judged,
|
|
1516
|
+
verdict: "guardrail_regressed",
|
|
1517
|
+
reason: regressed.map((metric) => `${metric.name} got ${percent(-metric.change)} worse, beyond the ${percent(limits.tolerance)} tolerance`).join("; ")
|
|
1518
|
+
};
|
|
1519
|
+
return primary.change > limits.threshold + primary.noise ? {
|
|
1520
|
+
...judged,
|
|
1521
|
+
verdict: "gain",
|
|
1522
|
+
reason: `${primary.name} improved ${percent(primary.change)}, past the ${percent(limits.threshold)} threshold and ${percent(primary.noise)} of noise`
|
|
1523
|
+
} : {
|
|
1524
|
+
...judged,
|
|
1525
|
+
verdict: "no_gain",
|
|
1526
|
+
reason: `${primary.name} changed ${percent(primary.change)}, within the ${percent(limits.threshold)} threshold and ${percent(primary.noise)} of noise`
|
|
1527
|
+
};
|
|
1528
|
+
};
|
|
1529
|
+
var floors = new WeakMap;
|
|
1530
|
+
var measure = (name, request) => takeStep(name, "measure", "measure", gen(function* () {
|
|
1531
|
+
const run = yield* LoopRun;
|
|
1532
|
+
const known = floors.get(run);
|
|
1533
|
+
const deferred = measureDeferred(name);
|
|
1534
|
+
yield* launch(deferred, (host, token) => host.startVerification({
|
|
1535
|
+
step: name,
|
|
1536
|
+
...request.head === undefined ? undefined : { revision: request.head },
|
|
1537
|
+
measure: {
|
|
1538
|
+
...request.base === undefined ? undefined : { base: request.base },
|
|
1539
|
+
plan: request.plan,
|
|
1540
|
+
samples: request.samples ?? 5,
|
|
1541
|
+
calibrate: known === undefined
|
|
1542
|
+
},
|
|
1543
|
+
token
|
|
1544
|
+
}));
|
|
1545
|
+
const evidence = yield* await_(deferred);
|
|
1546
|
+
const noise = known ?? noiseFloor(request.plan, evidence);
|
|
1547
|
+
if (known === undefined && incomplete(request.plan, evidence).length === 0)
|
|
1548
|
+
floors.set(run, noise);
|
|
1549
|
+
return judgeMeasurement(request.plan, evidence, noise, {
|
|
1550
|
+
threshold: request.threshold ?? 0.05,
|
|
1551
|
+
tolerance: request.tolerance ?? 0.02
|
|
1552
|
+
});
|
|
1553
|
+
}));
|
|
1554
|
+
|
|
1555
|
+
// packages/sdk/src/loop/test-loop.ts
|
|
1556
|
+
var LoopJournal = Struct({
|
|
1557
|
+
activities: Record(String4, Json),
|
|
1558
|
+
deferreds: Record(String4, Json)
|
|
1559
|
+
});
|
|
1560
|
+
|
|
1561
|
+
class ScriptedFailure extends TaggedClass("ScriptedFailure") {
|
|
1562
|
+
}
|
|
1563
|
+
// packages/sdk/src/loop/review.ts
|
|
1564
|
+
var Severity = Literals(["blocker", "major", "minor"]);
|
|
1565
|
+
var Finding = Struct({
|
|
1566
|
+
severity: Severity,
|
|
1567
|
+
file: String4,
|
|
1568
|
+
line: Int,
|
|
1569
|
+
detail: String4
|
|
1570
|
+
});
|
|
1571
|
+
var MergedFinding = Struct({
|
|
1572
|
+
id: String4,
|
|
1573
|
+
...Finding.fields,
|
|
1574
|
+
seats: ArraySchema(String4)
|
|
1575
|
+
});
|
|
1576
|
+
var Rebuttal = Struct({ findingId: String4, reason: String4 });
|
|
1577
|
+
var RebuttalVerdict = Struct({ findingId: String4, accepted: Boolean2 });
|
|
1578
|
+
var ScopeJudgement = Struct({ met: Boolean2, unmet: ArraySchema(String4) });
|
|
1579
|
+
var rank = { blocker: 0, major: 1, minor: 2 };
|
|
1580
|
+
var isBlocking = (finding) => finding.severity !== "minor";
|
|
1581
|
+
var mergeFindings = (bySeat) => {
|
|
1582
|
+
const merged = new Map;
|
|
1583
|
+
for (const [seat, findings] of Object.entries(bySeat))
|
|
1584
|
+
for (const finding of findings) {
|
|
1585
|
+
const id = `${finding.file}:${finding.line}`;
|
|
1586
|
+
const known = merged.get(id);
|
|
1587
|
+
const seats = [...new Set([...known?.seats ?? [], seat])];
|
|
1588
|
+
const worst = known === undefined || rank[finding.severity] < rank[known.severity] ? finding : known;
|
|
1589
|
+
merged.set(id, { id, severity: worst.severity, file: worst.file, line: worst.line, detail: worst.detail, seats });
|
|
1590
|
+
}
|
|
1591
|
+
return [...merged.values()].toSorted((left, right) => rank[left.severity] - rank[right.severity]);
|
|
1592
|
+
};
|
|
1593
|
+
var splitDisputed = (findings, rebuttals) => {
|
|
1594
|
+
const disputed = [];
|
|
1595
|
+
const undisputed = [];
|
|
1596
|
+
for (const finding of findings) {
|
|
1597
|
+
const rebuttal = rebuttals.find((entry) => entry.findingId === finding.id);
|
|
1598
|
+
if (rebuttal === undefined)
|
|
1599
|
+
undisputed.push(finding);
|
|
1600
|
+
else
|
|
1601
|
+
disputed.push({ finding, rebuttal });
|
|
1602
|
+
}
|
|
1603
|
+
return { disputed, undisputed };
|
|
1604
|
+
};
|
|
1605
|
+
var settleRound = (round) => {
|
|
1606
|
+
const { disputed, undisputed } = splitDisputed(round.findings, round.rebuttals);
|
|
1607
|
+
const accepted = (entry) => {
|
|
1608
|
+
const verdicts = round.verdicts.filter((verdict) => verdict.findingId === entry.finding.id);
|
|
1609
|
+
return verdicts.length > 0 && verdicts.every((verdict) => verdict.accepted);
|
|
1610
|
+
};
|
|
1611
|
+
return {
|
|
1612
|
+
open: undisputed,
|
|
1613
|
+
withdrawn: disputed.filter(accepted),
|
|
1614
|
+
standing: disputed.filter((entry) => !accepted(entry))
|
|
1615
|
+
};
|
|
1616
|
+
};
|
|
1617
|
+
var rallyStop = (input) => {
|
|
1618
|
+
const open = input.settled.open.filter(isBlocking).map((finding) => finding.id);
|
|
1619
|
+
const standing = input.settled.standing.flatMap((entry) => isBlocking(entry.finding) ? [entry.finding.id] : []);
|
|
1620
|
+
const unsettled = [...open, ...standing];
|
|
1621
|
+
const stop = (reason) => ({ stop: true, reason, unsettled });
|
|
1622
|
+
if (unsettled.length === 0)
|
|
1623
|
+
return stop("settled");
|
|
1624
|
+
if (standing.length > 0)
|
|
1625
|
+
return stop("dispute_stands");
|
|
1626
|
+
if (input.previous !== undefined && sameIds(input.previous, unsettled))
|
|
1627
|
+
return stop("findings_returned");
|
|
1628
|
+
return input.round >= input.maxRounds ? stop("round_cap") : { stop: false };
|
|
1629
|
+
};
|
|
1630
|
+
var sameIds = (left, right) => left.length === right.length && left.every((id) => right.includes(id));
|
|
1631
|
+
// packages/sdk/src/loop/check.ts
|
|
1632
|
+
class CheckFailed extends TaggedError2()("CheckFailed", {
|
|
1633
|
+
loop: String4,
|
|
1634
|
+
check: String4,
|
|
1635
|
+
reason: String4
|
|
1636
|
+
}) {
|
|
1637
|
+
get detail() {
|
|
1638
|
+
return `Check "${this.check}": ${this.reason}`;
|
|
1639
|
+
}
|
|
1640
|
+
get message() {
|
|
1641
|
+
return `Loop "${this.loop}": ${this.detail}`;
|
|
1642
|
+
}
|
|
1643
|
+
}
|
|
1644
|
+
|
|
1645
|
+
class StepNamedTwice extends TaggedError2()("StepNamedTwice", {
|
|
1646
|
+
loop: String4,
|
|
1647
|
+
check: String4,
|
|
1648
|
+
step: String4
|
|
1649
|
+
}) {
|
|
1650
|
+
get detail() {
|
|
1651
|
+
return `Check "${this.check}": Step "${this.step}" is named twice`;
|
|
1652
|
+
}
|
|
1653
|
+
get message() {
|
|
1654
|
+
return `Loop "${this.loop}": ${this.detail}`;
|
|
1655
|
+
}
|
|
1656
|
+
}
|
|
1657
|
+
|
|
1658
|
+
class ReplayDiverged extends TaggedError2()("ReplayDiverged", {
|
|
1659
|
+
loop: String4,
|
|
1660
|
+
check: String4,
|
|
1661
|
+
first: ArraySchema(String4),
|
|
1662
|
+
replay: ArraySchema(String4),
|
|
1663
|
+
rerun: ArraySchema(String4)
|
|
1664
|
+
}) {
|
|
1665
|
+
get detail() {
|
|
1666
|
+
const steps = (names) => names.join(", ") || "no Steps";
|
|
1667
|
+
return `Check "${this.check}": its replay from the journal diverged; it took ${steps(this.first)} and then ${steps(this.replay)}${this.rerun.length > 0 ? `, running ${this.rerun.join(", ")} again` : ""}. Keep effects and randomness inside Activities.`;
|
|
1668
|
+
}
|
|
1669
|
+
get message() {
|
|
1670
|
+
return `Loop "${this.loop}": ${this.detail}`;
|
|
1671
|
+
}
|
|
1672
|
+
}
|
|
1673
|
+
var LoopCheckError = Union([CheckFailed, StepNamedTwice, ReplayDiverged]);
|
|
1674
|
+
// packages/sdk/src/loop/sync.ts
|
|
1675
|
+
var UpToDate = Struct({ status: Literal("up_to_date") });
|
|
1676
|
+
var Conflict = Struct({
|
|
1677
|
+
status: Literal("conflict"),
|
|
1678
|
+
files: NonEmptyArray(String4),
|
|
1679
|
+
reason: String4
|
|
1680
|
+
});
|
|
1681
|
+
var merged = {
|
|
1682
|
+
status: Literal("merged"),
|
|
1683
|
+
settled: ArraySchema(String4)
|
|
1684
|
+
};
|
|
1685
|
+
var SyncAnswer = Union([UpToDate, Struct(merged), Conflict]);
|
|
1686
|
+
var BaseSync = Union([
|
|
1687
|
+
UpToDate,
|
|
1688
|
+
Struct({ ...merged, catchUp: optionalKey(CatchUp) }),
|
|
1689
|
+
Conflict
|
|
1690
|
+
]);
|
|
1691
|
+
var afterMerge = "One thing comes before any answer of merged, a clean merge included, and stopping above means stopping after it: before you answer merged, do what the repository's agent instructions say to do once the target branch is merged in, such as regenerating this branch's database migrations on top of the target's. Leave what that changes in the workspace: Kitman commits it.";
|
|
1692
|
+
var prompt = (target) => [
|
|
1693
|
+
`Kitman merged \`origin/${target}\` into this branch before you started, outside your sandbox, and says what came of it in a note after this brief. Do not fetch, as this workspace has no credential for the forge, and do not run git commands that write, such as \`git add\`, \`git commit\` or \`git merge --abort\`: Kitman finishes the merge itself from your answer.`,
|
|
1694
|
+
"If it was already up to date, change nothing and answer up_to_date. If it merged cleanly, answer merged with no settled files and stop: do not review or test anything else.",
|
|
1695
|
+
"If it conflicts, settle each file the note names so both sides' intent survives: leave no conflict marker, and for a file one side deleted or git could not mark, leave it as the version you want or delete it. Run the tests of the files you touched, and answer merged with those files under settled. Kitman then commits the files as you left them.",
|
|
1696
|
+
"If you cannot settle a file, answer conflict with the files and why: Kitman then aborts the whole merge.",
|
|
1697
|
+
"Never rebase, reset or force-push: this branch's history only grows."
|
|
1698
|
+
].concat(afterMerge).join(`
|
|
1699
|
+
|
|
1700
|
+
`);
|
|
1701
|
+
var syncBase = (name, options) => agentWorkAs(syncDeferred, name, {
|
|
1702
|
+
agent: options.agent,
|
|
1703
|
+
prompt: prompt(options.target ?? "HEAD"),
|
|
1704
|
+
output: BaseSync,
|
|
1705
|
+
answer: SyncAnswer,
|
|
1706
|
+
mergeTarget: options.target ?? "HEAD"
|
|
1707
|
+
});
|
|
1708
|
+
// packages/sdk/src/loop/continuing.ts
|
|
1709
|
+
var Continuing = Struct({
|
|
1710
|
+
changeRequestId: String4,
|
|
1711
|
+
number: String4,
|
|
1712
|
+
url: String4,
|
|
1713
|
+
branch: String4,
|
|
1714
|
+
targetBranch: String4,
|
|
1715
|
+
revision: optional(String4),
|
|
1716
|
+
lastRunId: optional(String4),
|
|
1717
|
+
lastRunStatus: optional(String4),
|
|
1718
|
+
lastRunSummary: optional(String4)
|
|
1719
|
+
});
|
|
1720
|
+
var continuingBrief = (continuing) => [
|
|
1721
|
+
`This continues the work on ${continuing.branch}, whose ChangeRequest is ${continuing.url}. Build on what is there; do not start over.`,
|
|
1722
|
+
...continuing.lastRunId === undefined ? [] : [
|
|
1723
|
+
`The last Run on it, ${continuing.lastRunId}, ended ${continuing.lastRunStatus ?? "unfinished"}${continuing.lastRunSummary === undefined ? "" : `: ${continuing.lastRunSummary}`}.`
|
|
1724
|
+
],
|
|
1725
|
+
...continuing.revision === undefined ? [] : [
|
|
1726
|
+
`It last pushed ${continuing.revision}. If the branch head is newer, someone pushed since: read \`git log ${continuing.revision}..HEAD\` first and keep their work.`
|
|
1727
|
+
],
|
|
1728
|
+
"The ChangeRequest's description lists what was left unsettled; settle those first."
|
|
1729
|
+
].join(`
|
|
1730
|
+
`);
|
|
1731
|
+
export { LoopManifest, AgentDeclaration, KitDeclarations, LoopOutcome, defineLoop, ManifestInvalid, make14, Suspended, failsOn, evidenceGate, ChildFailed, agentWork, agentWorkOnce, ask, call, waitFor, verify, PlanTickets, planWaves, ChangeRequestResult, RunFile, CreateTasksResult, ApproveChangeRequestResult, TranscriptPoint, changeRequest, writeBack, artifact, note, comment, createTasks, alertTask, integrationBranch, mergeChangeRequest, approveChangeRequest, closeChangeRequest, pipelineMoved, rerunPipeline, reportPipeline, release2, transcripts, propose, projectActivity, pipelineStatus, reviewThreads, openChangeRequests, ownChangeRequests, draftUpdate, claim, measure, Finding, MergedFinding, Rebuttal, RebuttalVerdict, ScopeJudgement, isBlocking, mergeFindings, settleRound, rallyStop, LoopCheckError, syncBase, Continuing, continuingBrief };
|