@kitman-sh/cli 0.0.0-stage → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,964 @@
1
+ // @bun
2
+ import {
3
+ dual,
4
+ hasProperty,
5
+ Prototype,
6
+ isNone,
7
+ Service2,
8
+ empty,
9
+ add,
10
+ getOrUndefined2,
11
+ get,
12
+ merge,
13
+ Reference,
14
+ fromInputUnsafe,
15
+ toMillis,
16
+ TaggedClass,
17
+ hasInterruptsOnly,
18
+ combine,
19
+ squash,
20
+ hasInterrupts,
21
+ isSuccess2,
22
+ addFinalizerExit,
23
+ effectDiscard,
24
+ min,
25
+ exponential,
26
+ spaced,
27
+ while_,
28
+ setInputType,
29
+ promise,
30
+ succeed5,
31
+ suspend,
32
+ sync,
33
+ void_2,
34
+ callback,
35
+ gen,
36
+ fail4,
37
+ failCause2,
38
+ die3,
39
+ try_,
40
+ yieldNow,
41
+ flatMap,
42
+ andThen,
43
+ tap,
44
+ map3,
45
+ catch_,
46
+ mapError,
47
+ orDie,
48
+ retry,
49
+ sandbox,
50
+ matchEffect,
51
+ context,
52
+ contextWith,
53
+ provideContext,
54
+ provideService,
55
+ acquireUseRelease,
56
+ onExit,
57
+ interruptible,
58
+ uninterruptibleMask,
59
+ annotateCurrentSpan,
60
+ withSpan,
61
+ fnUntraced,
62
+ getCurrent,
63
+ encode2,
64
+ transform,
65
+ encodeBase64Url,
66
+ decodeBase64UrlString,
67
+ decodeUnknownEffect,
68
+ decodeEffect,
69
+ decodeSync,
70
+ encodeUnknownEffect,
71
+ encodeEffect,
72
+ encodeSync,
73
+ isSchema,
74
+ optionalKey,
75
+ optional,
76
+ Literal,
77
+ Never,
78
+ Unknown,
79
+ String2,
80
+ Boolean2,
81
+ Void,
82
+ Struct,
83
+ Record,
84
+ Tuple,
85
+ ArraySchema,
86
+ Union,
87
+ Literals,
88
+ decodeTo,
89
+ tag,
90
+ makeFilter,
91
+ Finite,
92
+ Int,
93
+ Defect,
94
+ fromJsonString,
95
+ Cause,
96
+ Exit,
97
+ Class,
98
+ TaggedError2,
99
+ toJsonSchemaDocument,
100
+ toCodecJson,
101
+ Json
102
+ } from "./chunk-txyq8r41.js";
103
+ import {
104
+ LoopCapabilities
105
+ } from "./chunk-hrvcz0m4.js";
106
+
107
+ // packages/sdk/src/loop/define.ts
108
+ var LoopOutcome = Literals(["feature", "bug", "refactor", "investigation", "docs", "migration"]);
109
+ var defineLoop = (definition) => definition;
110
+
111
+ class ManifestInvalid extends TaggedError2()("ManifestInvalid", {
112
+ loop: String2,
113
+ message: String2
114
+ }) {
115
+ }
116
+ var jsonSchemaOf = (loop, schema) => try_({
117
+ try: () => toJsonSchemaDocument(schema),
118
+ catch: (error) => new ManifestInvalid({ loop, message: `Schema has no JSON Schema: ${String(error)}` })
119
+ }).pipe(flatMap((document) => decodeUnknownEffect(JsonObjectSchema)({ ...document.schema, $defs: document.definitions }).pipe(mapError((error) => new ManifestInvalid({ loop, message: error.message })))));
120
+ var JsonObjectSchema = Record(String2, Json);
121
+ // node_modules/.bun/effect@4.0.4/node_modules/effect/dist/workflow/internal/crypto.js
122
+ var makeHashDigest = (original) => map3(promise(() => crypto.subtle.digest("SHA-256", new TextEncoder().encode(original))), (buffer) => {
123
+ const data = new Uint8Array(buffer);
124
+ let hexString = "";
125
+ for (let i = 0;i < 16; i++) {
126
+ hexString += data[i].toString(16).padStart(2, "0");
127
+ }
128
+ return hexString;
129
+ });
130
+
131
+ // node_modules/.bun/effect@4.0.4/node_modules/effect/dist/workflow/Workflow.js
132
+ var TypeId = "~effect/workflow/Workflow";
133
+ var EngineTag = /* @__PURE__ */ Service2("effect/workflow/WorkflowEngine");
134
+ var InstanceTag = /* @__PURE__ */ Service2("effect/workflow/WorkflowEngine/WorkflowInstance");
135
+ var makeExecutionIdFromPayload = (self, payload) => makeHashDigest(`${self._tag.length}:${self._tag}:${self.idempotencyKey(payload)}`);
136
+ var Proto = {
137
+ [TypeId]: TypeId,
138
+ annotate(tag, value) {
139
+ return makeProto({
140
+ _tag: this._tag,
141
+ payloadSchema: this.payloadSchema,
142
+ successSchema: this.successSchema,
143
+ errorSchema: this.errorSchema,
144
+ annotations: add(this.annotations, tag, value),
145
+ idempotencyKey: this.idempotencyKey,
146
+ suspendedRetrySchedule: this.suspendedRetrySchedule
147
+ });
148
+ },
149
+ annotateMerge(context) {
150
+ return makeProto({
151
+ _tag: this._tag,
152
+ payloadSchema: this.payloadSchema,
153
+ successSchema: this.successSchema,
154
+ errorSchema: this.errorSchema,
155
+ annotations: merge(this.annotations, context),
156
+ idempotencyKey: this.idempotencyKey,
157
+ suspendedRetrySchedule: this.suspendedRetrySchedule
158
+ });
159
+ },
160
+ execute(fields, opts) {
161
+ return suspend(() => {
162
+ const payload = this.payloadSchema.make(fields);
163
+ const run = flatMap(EngineTag, (engine) => flatMap(makeExecutionIdFromPayload(this, payload), (executionId) => andThen(annotateCurrentSpan({
164
+ executionId
165
+ }), engine.execute(this, {
166
+ executionId,
167
+ payload,
168
+ discard: opts?.discard,
169
+ suspendedRetrySchedule: this.suspendedRetrySchedule
170
+ }))));
171
+ return opts?.discard ? run : withPendingActivity(run);
172
+ }).pipe(withSpan(`${this._tag}.execute`, {}, {
173
+ captureStackTrace: false
174
+ }));
175
+ },
176
+ poll(executionId) {
177
+ return flatMap(EngineTag, (engine) => engine.poll(this, executionId)).pipe(withSpan(`${this._tag}.poll`, {
178
+ attributes: {
179
+ executionId
180
+ }
181
+ }, {
182
+ captureStackTrace: false
183
+ }));
184
+ },
185
+ interrupt(executionId) {
186
+ return flatMap(EngineTag, (engine) => engine.interrupt(this, executionId)).pipe(withSpan(`${this._tag}.interrupt`, {
187
+ attributes: {
188
+ executionId
189
+ }
190
+ }, {
191
+ captureStackTrace: false
192
+ }));
193
+ },
194
+ resume(executionId) {
195
+ return flatMap(EngineTag, (engine) => engine.resume(this, executionId)).pipe(withSpan(`${this._tag}.resume`, {
196
+ attributes: {
197
+ executionId
198
+ }
199
+ }, {
200
+ captureStackTrace: false
201
+ }));
202
+ },
203
+ toLayer(execute) {
204
+ return effectDiscard(flatMap(EngineTag, (engine) => engine.register(this, execute)));
205
+ },
206
+ executionId(payload) {
207
+ return flatMap(orDie(this.payloadSchema.makeEffect(payload)), (payload) => makeExecutionIdFromPayload(this, payload));
208
+ },
209
+ withCompensation: (...args) => withCompensation(...args)
210
+ };
211
+ var makeProto = (options) => {
212
+ function Workflow() {}
213
+ Object.setPrototypeOf(Workflow, Proto);
214
+ Object.assign(Workflow, options);
215
+ return Workflow;
216
+ };
217
+ var make = (tag, options) => makeProto({
218
+ _tag: tag,
219
+ payloadSchema: isSchema(options.payload) ? options.payload : Struct(options.payload),
220
+ successSchema: options.success ?? Void,
221
+ errorSchema: options.error ?? Never,
222
+ annotations: options.annotations ?? empty(),
223
+ idempotencyKey: options.idempotencyKey,
224
+ suspendedRetrySchedule: options.suspendedRetrySchedule
225
+ });
226
+ var ResultTypeId = "~effect/workflow/Workflow/Result";
227
+ var isResult = (u) => hasProperty(u, ResultTypeId);
228
+ class Suspended extends (/* @__PURE__ */ Class("effect/workflow/Workflow/Suspended")({
229
+ _tag: /* @__PURE__ */ tag("Suspended"),
230
+ cause: /* @__PURE__ */ optional(/* @__PURE__ */ Cause(Never, /* @__PURE__ */ Defect()))
231
+ })) {
232
+ [ResultTypeId] = ResultTypeId;
233
+ }
234
+ var wrapActivityResult = (effect, isSuspend) => contextWith((context) => {
235
+ const instance = get(context, InstanceTag);
236
+ return acquireUseRelease(sync(() => adoptActivityUnsafe(context, instance) ?? registerActivityUnsafe(instance)), () => effect, (registration, exit) => {
237
+ releaseActivityUnsafe(registration);
238
+ const isSuspended = isSuccess2(exit) && isSuspend(exit.value);
239
+ if (isSuccess2(exit) && isResult(exit.value) && exit.value._tag === "Suspended" && exit.value.cause) {
240
+ instance.cause = instance.cause ? combine(instance.cause, exit.value.cause) : exit.value.cause;
241
+ }
242
+ return isSuspended && instance.activityState.count > 0 ? waitForZero(instance) : void_2;
243
+ });
244
+ });
245
+ var PendingActivityRegistration = /* @__PURE__ */ Service2("effect/workflow/Workflow/PendingActivityRegistration");
246
+ var registerActivityUnsafe = (instance) => {
247
+ const state = instance.activityState;
248
+ if (state.count === 0)
249
+ state.latch.closeUnsafe();
250
+ state.count++;
251
+ return {
252
+ instance,
253
+ state: "pending"
254
+ };
255
+ };
256
+ var adoptActivityUnsafe = (context, instance) => {
257
+ const pending = getOrUndefined2(context, PendingActivityRegistration);
258
+ if (!pending || pending.instance !== instance) {
259
+ return;
260
+ }
261
+ if (pending.state !== "pending") {
262
+ throw new Error("Workflow.wrapActivityResult: pending child registration has already been consumed");
263
+ }
264
+ pending.state = "adopted";
265
+ return pending;
266
+ };
267
+ var releaseActivityUnsafe = (registration) => {
268
+ if (registration.state === "released")
269
+ return;
270
+ registration.state = "released";
271
+ const state = registration.instance.activityState;
272
+ state.count--;
273
+ if (state.count === 0)
274
+ state.latch.openUnsafe();
275
+ };
276
+ var withPendingActivity = (effect) => contextWith((context) => {
277
+ const instance = getOrUndefined2(context, InstanceTag);
278
+ if (!instance)
279
+ return effect;
280
+ return acquireUseRelease(sync(() => registerActivityUnsafe(instance)), (registration) => provideService(effect, PendingActivityRegistration, registration), (registration) => sync(() => releaseActivityUnsafe(registration)));
281
+ });
282
+ var waitForZero = /* @__PURE__ */ fnUntraced(function* (instance) {
283
+ const state = instance.activityState;
284
+ while (true) {
285
+ if (state.count > 0) {
286
+ yield* state.latch.await;
287
+ yield* yieldNow;
288
+ continue;
289
+ }
290
+ yield* yieldNow;
291
+ if (state.count === 0)
292
+ return;
293
+ }
294
+ });
295
+ var addFinalizer = /* @__PURE__ */ fnUntraced(function* (f) {
296
+ const instance = yield* InstanceTag;
297
+ const services = yield* context();
298
+ yield* addFinalizerExit(instance.scope, (exit) => instance.abandoned ? void_2 : provideContext(f(exit), services));
299
+ });
300
+ var withCompensation = /* @__PURE__ */ dual(2, (effect, compensation) => uninterruptibleMask((restore) => tap(restore(effect), (value) => addFinalizer((exit) => isSuccess2(exit) ? void_2 : compensation(value, exit.cause)))));
301
+ var suspend2 = (instance) => interruptible(callback(() => {
302
+ instance.suspended = true;
303
+ const fiber = getCurrent();
304
+ fiber.interruptUnsafe(fiber.id);
305
+ }));
306
+
307
+ // node_modules/.bun/effect@4.0.4/node_modules/effect/dist/workflow/DurableDeferred.js
308
+ var TypeId2 = "~effect/workflow/DurableDeferred";
309
+ var make2 = (name, options) => {
310
+ const successSchema = options?.success ?? Void;
311
+ const errorSchema = options?.error ?? Never;
312
+ return {
313
+ [TypeId2]: TypeId2,
314
+ name,
315
+ successSchema,
316
+ errorSchema,
317
+ exitSchema: Exit(toCodecJson(successSchema), toCodecJson(errorSchema), toCodecJson(Defect())),
318
+ withActivityAttempt: gen(function* () {
319
+ const attempt = yield* CurrentAttempt;
320
+ return make2(`${name}/${attempt}`, {
321
+ success: successSchema,
322
+ error: errorSchema
323
+ });
324
+ })
325
+ };
326
+ };
327
+ var EngineTag2 = /* @__PURE__ */ Service2("effect/workflow/WorkflowEngine");
328
+ var InstanceTag2 = /* @__PURE__ */ Service2("effect/workflow/WorkflowEngine/WorkflowInstance");
329
+ var CurrentAttempt = /* @__PURE__ */ Reference("effect/workflow/Activity/CurrentAttempt", {
330
+ defaultValue: () => 1
331
+ });
332
+ var awaitOwners = /* @__PURE__ */ new WeakMap;
333
+ var registerAwait = (instance, name) => {
334
+ instance.awaitedDeferreds.set(name, (instance.awaitedDeferreds.get(name) ?? 0) + 1);
335
+ awaitOwners.get(instance)?.push(name);
336
+ };
337
+ var await_ = /* @__PURE__ */ fnUntraced(function* (self) {
338
+ const engine = yield* EngineTag2;
339
+ const instance = yield* InstanceTag2;
340
+ registerAwait(instance, self.name);
341
+ const exit = yield* wrapActivityResult(engine.deferredResult(self), isNone);
342
+ if (isNone(exit)) {
343
+ return yield* suspend2(instance);
344
+ }
345
+ return yield* exit.value;
346
+ });
347
+ class TokenParsed extends (/* @__PURE__ */ Class("effect/workflow/DurableDeferred/TokenParsed")({
348
+ workflowName: String2,
349
+ executionId: String2,
350
+ deferredName: String2
351
+ })) {
352
+ get asToken() {
353
+ return encode2(JSON.stringify([this.workflowName, this.executionId, this.deferredName]));
354
+ }
355
+ static FromString = /* @__PURE__ */ String2.pipe(/* @__PURE__ */ decodeTo(/* @__PURE__ */ fromJsonString(/* @__PURE__ */ Tuple([String2, String2, String2])), {
356
+ decode: /* @__PURE__ */ decodeBase64UrlString(),
357
+ encode: /* @__PURE__ */ encodeBase64Url()
358
+ }), /* @__PURE__ */ decodeTo(TokenParsed, {
359
+ decode: /* @__PURE__ */ transform(([workflowName, executionId, deferredName]) => new TokenParsed({
360
+ workflowName,
361
+ executionId,
362
+ deferredName
363
+ })),
364
+ encode: /* @__PURE__ */ transform((parsed) => [parsed.workflowName, parsed.executionId, parsed.deferredName])
365
+ }));
366
+ static fromString = /* @__PURE__ */ decodeSync(TokenParsed.FromString);
367
+ static encode = /* @__PURE__ */ encodeSync(TokenParsed.FromString);
368
+ }
369
+ var token = /* @__PURE__ */ fnUntraced(function* (self) {
370
+ const instance = yield* InstanceTag2;
371
+ return tokenFromExecutionId(self, instance);
372
+ });
373
+ var tokenFromExecutionId = /* @__PURE__ */ dual(2, (self, options) => new TokenParsed({
374
+ workflowName: options.workflow._tag,
375
+ executionId: options.executionId,
376
+ deferredName: self.name
377
+ }).asToken);
378
+
379
+ // node_modules/.bun/effect@4.0.4/node_modules/effect/dist/workflow/Activity.js
380
+ var TypeId3 = "~effect/workflow/Activity";
381
+ var make3 = (options) => {
382
+ const successSchema = options.success ?? Void;
383
+ const errorSchema = options.error ?? Never;
384
+ const successSchemaJson = toCodecJson(successSchema);
385
+ const errorSchemaJson = toCodecJson(errorSchema);
386
+ let execute;
387
+ const executeWithoutInterrupt = retryOnInterrupt(options.name, options.interruptRetryPolicy)(options.execute);
388
+ const self = {
389
+ ...Prototype({
390
+ label: "Activity",
391
+ evaluate(_) {
392
+ return execute;
393
+ }
394
+ }),
395
+ [TypeId3]: TypeId3,
396
+ name: options.name,
397
+ successSchema,
398
+ errorSchema,
399
+ exitSchema: Exit(successSchemaJson, errorSchemaJson, Defect()),
400
+ exitSchemaPartial: Exit(successSchemaJson, errorSchemaJson, Unknown),
401
+ annotations: options.annotations ?? empty(),
402
+ annotate(tag, value) {
403
+ return make3({
404
+ ...options,
405
+ annotations: add(self.annotations, tag, value)
406
+ });
407
+ },
408
+ annotateMerge(context) {
409
+ return make3({
410
+ ...options,
411
+ annotations: merge(self.annotations, context)
412
+ });
413
+ },
414
+ execute: executeWithoutInterrupt,
415
+ executeEncoded: matchEffect(executeWithoutInterrupt, {
416
+ onFailure: (error) => flatMap(orDie(encodeEffect(errorSchemaJson)(error)), fail4),
417
+ onSuccess: (value) => orDie(encodeEffect(successSchemaJson)(value))
418
+ })
419
+ };
420
+ execute = makeExecute(self);
421
+ return self;
422
+ };
423
+ var interruptRetryPolicy = /* @__PURE__ */ min([exponential(400, 1.5), spaced("10 seconds")]).pipe(/* @__PURE__ */ setInputType(), /* @__PURE__ */ while_((meta) => meta.attempt <= 10 && hasInterrupts(meta.input)));
424
+ var retryOnInterrupt = (name, policy = interruptRetryPolicy) => (effect) => flatMap(InstanceTag3, (instance) => effect.pipe(sandbox, retry({
425
+ schedule: policy,
426
+ while: () => !instance.suspended
427
+ }), catch_((cause) => hasInterrupts(cause) && !instance.suspended ? die3(`Activity "${name}" interrupted and retry attempts exhausted`) : failCause2(cause))));
428
+ var CurrentAttempt2 = /* @__PURE__ */ Reference("effect/workflow/Activity/CurrentAttempt", {
429
+ defaultValue: () => 1
430
+ });
431
+ var EngineTag3 = /* @__PURE__ */ Service2("effect/workflow/WorkflowEngine");
432
+ var InstanceTag3 = /* @__PURE__ */ Service2("effect/workflow/WorkflowEngine/WorkflowInstance");
433
+ var makeExecute = /* @__PURE__ */ fnUntraced(function* (activity) {
434
+ const engine = yield* EngineTag3;
435
+ const instance = yield* InstanceTag3;
436
+ const attempt = yield* CurrentAttempt2;
437
+ yield* annotateCurrentSpan({
438
+ executionId: instance.executionId
439
+ });
440
+ const result = yield* wrapActivityResult(engine.activityExecute(activity, attempt), (_) => _._tag === "Suspended");
441
+ if (result._tag === "Suspended") {
442
+ return yield* suspend2(instance);
443
+ }
444
+ return yield* result.exit;
445
+ }, (effect, activity) => withSpan(effect, activity.name, {
446
+ captureStackTrace: false
447
+ }));
448
+ // packages/sdk/src/loop/evidence.ts
449
+ var EvidenceCheck = Struct({
450
+ name: String2,
451
+ command: String2,
452
+ status: Literals(["passed", "failed"]),
453
+ preExisting: Boolean2,
454
+ durationMs: Finite,
455
+ evidenceId: String2
456
+ });
457
+ var VerifyResult = Struct({
458
+ revision: String2,
459
+ tree: String2,
460
+ passed: Boolean2,
461
+ checks: ArraySchema(EvidenceCheck)
462
+ });
463
+ var verdict = (reasons) => reasons.length === 0 ? { settled: true } : { settled: false, reasons };
464
+ var missing = (side) => `No verification evidence for the ${side}`;
465
+ var allPass = (side, result) => {
466
+ if (result === undefined)
467
+ return [missing(side)];
468
+ if (result.checks.length === 0)
469
+ return [`No approved verification ran on the ${side} tree ${result.tree}`];
470
+ return result.checks.filter((check) => check.status === "failed" && !check.preExisting).map((check) => `${check.name} fails on the ${side} tree ${result.tree}`);
471
+ };
472
+ var checkOn = (side, result, name) => {
473
+ if (result === undefined)
474
+ return { reason: missing(side) };
475
+ if (name === undefined)
476
+ return { reason: `No check was named for the ${side}` };
477
+ const found = result.checks.find((check) => check.name === name);
478
+ return found === undefined ? { reason: `No evidence for ${name} on the ${side} tree ${result.tree}` } : { found };
479
+ };
480
+ var passesOnHead = (head, name) => {
481
+ const { found, reason } = checkOn("head", head, name);
482
+ if (found === undefined)
483
+ return [reason];
484
+ return found.status === "passed" ? [] : [`${found.name} fails on the head tree ${head?.tree}`];
485
+ };
486
+ var bugReasons = (input) => {
487
+ const base = checkOn("base", input.base, input.reproducing);
488
+ const head = checkOn("head", input.head, input.reproducing);
489
+ return [
490
+ ...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`],
491
+ ...head.found === undefined ? [head.reason] : head.found.status === "passed" ? [] : [`${head.found.name} fails on the head tree ${input.head?.tree}`]
492
+ ];
493
+ };
494
+ var conclusionReasons = (conclusion) => {
495
+ if (conclusion === undefined || conclusion.text.trim() === "")
496
+ return ["No conclusion was given"];
497
+ return conclusion.sources.length === 0 ? ["The conclusion names no sources"] : [];
498
+ };
499
+ var scopeReasons = (scope) => {
500
+ if (scope === undefined)
501
+ return ["Review has not judged the scope"];
502
+ if (scope.met)
503
+ return [];
504
+ return scope.unmet.length === 0 ? ["Review found the scope unmet"] : scope.unmet.map((item) => `Review found the scope unmet: ${item}`);
505
+ };
506
+ var evidenceGate = (input) => {
507
+ switch (input.outcome) {
508
+ case "feature":
509
+ return verdict([...allPass("head", input.head), ...scopeReasons(input.review)]);
510
+ case "bug":
511
+ return verdict(bugReasons(input));
512
+ case "refactor":
513
+ return verdict([...allPass("base", input.base), ...allPass("head", input.head)]);
514
+ case "investigation":
515
+ return verdict(conclusionReasons(input.conclusion));
516
+ case "docs":
517
+ return verdict((input.documented ?? []).length === 0 ? ["No documented command was named"] : (input.documented ?? []).flatMap((name) => passesOnHead(input.head, name)));
518
+ case "migration":
519
+ return verdict(passesOnHead(input.head, input.rollback));
520
+ default:
521
+ return verdict(allPass("head", input.head));
522
+ }
523
+ };
524
+
525
+ // packages/sdk/src/loop/steps.ts
526
+ class StepFailed extends TaggedError2()("StepFailed", {
527
+ step: String2,
528
+ reason: String2
529
+ }) {
530
+ get message() {
531
+ return `Step "${this.step}" failed: ${this.reason}`;
532
+ }
533
+ }
534
+
535
+ class OutputInvalid extends TaggedError2()("OutputInvalid", {
536
+ step: String2,
537
+ message: String2
538
+ }) {
539
+ }
540
+
541
+ class QuestionRefused extends TaggedError2()("QuestionRefused", {
542
+ step: String2,
543
+ answer: String2,
544
+ options: ArraySchema(String2)
545
+ }) {
546
+ }
547
+
548
+ class WaitTimedOut extends TaggedError2()("WaitTimedOut", {
549
+ step: String2,
550
+ event: String2
551
+ }) {
552
+ }
553
+
554
+ class ChildFailed extends TaggedError2()("ChildFailed", {
555
+ step: String2,
556
+ loop: String2,
557
+ reason: String2
558
+ }) {
559
+ get message() {
560
+ return `Child Run of "${this.loop}" for Step "${this.step}" failed: ${this.reason}`;
561
+ }
562
+ }
563
+
564
+ class CapabilityDenied extends TaggedError2()("CapabilityDenied", {
565
+ step: String2,
566
+ capability: Literals(LoopCapabilities),
567
+ secret: optionalKey(String2)
568
+ }) {
569
+ get message() {
570
+ 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`;
571
+ }
572
+ }
573
+
574
+ class DuplicateStep extends TaggedError2()("DuplicateStep", {
575
+ step: String2
576
+ }) {
577
+ }
578
+
579
+ class InputInvalid extends TaggedError2()("InputInvalid", {
580
+ loop: String2,
581
+ message: String2
582
+ }) {
583
+ }
584
+ var LoopEvent = Struct({ type: String2, payload: Record(String2, Json) });
585
+
586
+ class LoopRun extends Service2()("@kitman-sh/sdk/loop/LoopRun") {
587
+ }
588
+
589
+ class LoopHost extends Service2()("@kitman-sh/sdk/loop/LoopHost") {
590
+ }
591
+ var agentWorkDeferred = (step) => make2(`agent_work/${step}`, { success: Json, error: StepFailed });
592
+ var answerDeferred = (step) => make2(`ask/${step}`, { success: String2, error: StepFailed });
593
+ var childDeferred = (step) => make2(`call/${step}`, { success: Json, error: ChildFailed });
594
+ var eventDeferred = (step) => make2(`wait_for/${step}`, { success: LoopEvent, error: WaitTimedOut });
595
+ var verifyDeferred = (step) => make2(`verify/${step}`, { success: VerifyResult, error: StepFailed });
596
+ var recordStep = (name, kind, exit) => {
597
+ if (isSuccess2(exit))
598
+ return { name, kind, status: "succeeded", result: exit.value };
599
+ if (hasInterruptsOnly(exit.cause))
600
+ return;
601
+ return { name, kind, status: "failed", error: squash(exit.cause) };
602
+ };
603
+ var takeStep = (name, kind, capability, body) => gen(function* () {
604
+ const run = yield* LoopRun;
605
+ if (run.names.has(name))
606
+ return yield* new DuplicateStep({ step: name });
607
+ if (capability !== undefined && !run.granted.has(capability))
608
+ return yield* new CapabilityDenied({ step: name, capability });
609
+ run.names.add(name);
610
+ return yield* body.pipe(onExit((exit) => sync(() => {
611
+ const record = recordStep(name, kind, exit);
612
+ if (record !== undefined)
613
+ run.steps.push(record);
614
+ })));
615
+ });
616
+ var launch = (deferred, start) => make3({
617
+ name: deferred.name,
618
+ error: StepFailed,
619
+ execute: gen(function* () {
620
+ return yield* start(yield* LoopHost, yield* token(deferred));
621
+ })
622
+ });
623
+ var toJson = (step, schema, value) => encodeUnknownEffect(toCodecJson(schema))(value).pipe(flatMap(decodeUnknownEffect(Json)), mapError((error) => new StepFailed({ step, reason: error.message })));
624
+ var agentWork = (name, options) => takeStep(name, "agent_work", "agent_work", gen(function* () {
625
+ const run = yield* LoopRun;
626
+ const agent = run.agents[options.agent];
627
+ const undeclared = options.secrets?.find((secret) => !run.secrets.has(secret));
628
+ if (undeclared !== undefined)
629
+ return yield* new CapabilityDenied({ step: name, capability: "agent_work", secret: undeclared });
630
+ if (agent === undefined)
631
+ return yield* new StepFailed({ step: name, reason: `Agent role "${options.agent}" is not declared` });
632
+ const deferred = agentWorkDeferred(name);
633
+ const output = yield* jsonSchemaOf(run.loop, options.output).pipe(mapError((error) => new StepFailed({ step: name, reason: error.message })));
634
+ yield* launch(deferred, (host, token2) => host.startAgentWork({
635
+ step: name,
636
+ role: options.agent,
637
+ agent,
638
+ prompt: options.prompt,
639
+ output,
640
+ ...options.secrets === undefined ? undefined : { secrets: options.secrets },
641
+ token: token2
642
+ }));
643
+ const submitted = yield* await_(deferred);
644
+ return yield* decodeEffect(toCodecJson(options.output))(submitted).pipe(mapError((error) => new OutputInvalid({ step: name, message: error.message })));
645
+ }));
646
+ var ask = (name, question) => takeStep(name, "ask", "ask", gen(function* () {
647
+ const deferred = answerDeferred(name);
648
+ const options = "options" in question ? question.options : undefined;
649
+ yield* launch(deferred, (host, token2) => host.putQuestion({
650
+ step: name,
651
+ prompt: question.prompt,
652
+ ...options === undefined ? undefined : { options },
653
+ token: token2
654
+ }));
655
+ const answer = yield* await_(deferred);
656
+ if (options === undefined)
657
+ return answer;
658
+ const offered = options.find((option) => option === answer);
659
+ if (offered === undefined)
660
+ return yield* new QuestionRefused({ step: name, answer, options });
661
+ return offered;
662
+ }));
663
+ var call = (name, loop, input) => takeStep(name, "call", "call", gen(function* () {
664
+ const deferred = childDeferred(name);
665
+ const encoded = yield* toJson(name, loop.input, input);
666
+ yield* launch(deferred, (host, token2) => host.admitChild({ step: name, loop: loop.id, input: encoded, token: token2 }));
667
+ const result = yield* await_(deferred);
668
+ return yield* decodeEffect(toCodecJson(loop.output))(result).pipe(mapError((error) => new ChildFailed({ step: name, loop: loop.id, reason: error.message })));
669
+ }));
670
+ var waitFor = (name, wait) => takeStep(name, "wait_for", undefined, gen(function* () {
671
+ const deferred = eventDeferred(name);
672
+ const timeoutMillis = toMillis(fromInputUnsafe(wait.timeout));
673
+ yield* launch(deferred, (host, token2) => host.awaitEvent({
674
+ step: name,
675
+ event: wait.event,
676
+ ...wait.filter === undefined ? undefined : { filter: wait.filter },
677
+ timeoutMillis,
678
+ token: token2
679
+ }));
680
+ return yield* await_(deferred);
681
+ }));
682
+ var verify = (name, request) => takeStep(name, "verify", "verify", gen(function* () {
683
+ const deferred = verifyDeferred(name);
684
+ yield* launch(deferred, (host, token2) => host.startVerification({
685
+ step: name,
686
+ ...request.revision === undefined ? undefined : { revision: request.revision },
687
+ ...request.checks === undefined ? undefined : { checks: request.checks },
688
+ token: token2
689
+ }));
690
+ return yield* await_(deferred);
691
+ }));
692
+ // packages/sdk/src/loop/plan.ts
693
+ var PlanTicket = Struct({
694
+ key: String2,
695
+ title: String2,
696
+ body: String2,
697
+ acceptanceCriteria: ArraySchema(String2),
698
+ repoBindingId: optional(String2),
699
+ blockedBy: ArraySchema(String2),
700
+ outcome: optional(LoopOutcome)
701
+ });
702
+ var cycleMessage = (keys) => `These tickets block each other in a cycle, so none can start: ${keys.join(", ")}`;
703
+ var ticketsProblem = (tickets) => {
704
+ const keys = new Set;
705
+ for (const ticket of tickets) {
706
+ if (keys.has(ticket.key))
707
+ return `Two tickets have the key "${ticket.key}"`;
708
+ keys.add(ticket.key);
709
+ }
710
+ for (const ticket of tickets)
711
+ for (const blocker of ticket.blockedBy)
712
+ if (!keys.has(blocker))
713
+ return `Ticket "${ticket.key}" is blocked by "${blocker}", which is not a ticket`;
714
+ const { blocked } = wavesOf(tickets);
715
+ return blocked.length === 0 ? undefined : cycleMessage(blocked);
716
+ };
717
+ var PlanTickets = ArraySchema(PlanTicket).check(makeFilter((tickets) => ticketsProblem(tickets) ?? true));
718
+
719
+ class BlockingCycle extends TaggedError2()("BlockingCycle", {
720
+ tickets: ArraySchema(String2)
721
+ }) {
722
+ get message() {
723
+ return cycleMessage(this.tickets);
724
+ }
725
+ }
726
+ var byRepoBinding = (left, right) => (left.repoBindingId ?? "").localeCompare(right.repoBindingId ?? "");
727
+ function wavesOf(tickets) {
728
+ const placed = new Set;
729
+ const waves = [];
730
+ let left = tickets;
731
+ while (left.length > 0) {
732
+ const ready = left.filter((ticket) => ticket.blockedBy.every((blocker) => placed.has(blocker)));
733
+ if (ready.length === 0)
734
+ break;
735
+ for (const ticket of ready)
736
+ placed.add(ticket.key);
737
+ waves.push(ready.toSorted(byRepoBinding));
738
+ left = left.filter((ticket) => !placed.has(ticket.key));
739
+ }
740
+ return { waves, blocked: left.map((ticket) => ticket.key) };
741
+ }
742
+ var planWaves = (tickets) => suspend(() => {
743
+ const { waves, blocked } = wavesOf(tickets);
744
+ return blocked.length === 0 ? succeed5(waves) : fail4(new BlockingCycle({ tickets: blocked }));
745
+ });
746
+
747
+ // packages/sdk/src/loop/activities.ts
748
+ var ChangeRequestRequest = Struct({
749
+ title: String2,
750
+ body: String2,
751
+ integration: optional(String2)
752
+ });
753
+ var ChangeRequestResult = Struct({ id: String2, number: String2, url: String2 });
754
+ var WriteBackMilestones = ["started", "change_request_opened", "merged", "failed"];
755
+ var WriteBackRequest = Struct({
756
+ milestone: optional(Literals(WriteBackMilestones)),
757
+ changeRequestUrl: optional(String2)
758
+ });
759
+ var ArtifactRequest = Struct({
760
+ kind: String2,
761
+ title: String2,
762
+ text: String2,
763
+ data: optional(Json)
764
+ });
765
+ var ArtifactResult = Struct({ artifactId: String2 });
766
+ var NoteRequest = Struct({ text: String2, artifactId: optional(String2) });
767
+ var CreateTasksRequest = Struct({ tickets: ArraySchema(PlanTicket) });
768
+ var CreateTasksResult = Struct({
769
+ tasks: ArraySchema(Struct({ key: String2, taskId: String2 }))
770
+ });
771
+ var IntegrationBranchRequest = Struct({ repoBindingId: optional(String2) });
772
+ var IntegrationBranch = Struct({
773
+ repoBindingId: String2,
774
+ branch: String2,
775
+ revision: String2
776
+ });
777
+ var MergeChangeRequestRequest = Struct({ changeRequestId: String2 });
778
+ var MergeResult = Union([
779
+ Struct({ status: Literal("merged"), revision: String2 }),
780
+ Struct({ status: Literal("conflict") })
781
+ ]);
782
+ var CommentRequest = Struct({ changeRequestId: String2, body: String2 });
783
+ var ReleaseRequest = Struct({
784
+ tag: String2,
785
+ revision: optional(String2),
786
+ title: String2,
787
+ notes: String2
788
+ });
789
+ var ReleaseResult = Struct({ tag: String2, revision: String2, url: String2 });
790
+
791
+ class ChangeRequestActivity extends Service2()("@kitman-sh/sdk/loop/ChangeRequestActivity") {
792
+ }
793
+
794
+ class WriteBackActivity extends Service2()("@kitman-sh/sdk/loop/WriteBackActivity") {
795
+ }
796
+
797
+ class ArtifactActivity extends Service2()("@kitman-sh/sdk/loop/ArtifactActivity") {
798
+ }
799
+
800
+ class NoteActivity extends Service2()("@kitman-sh/sdk/loop/NoteActivity") {
801
+ }
802
+
803
+ class CommentActivity extends Service2()("@kitman-sh/sdk/loop/CommentActivity") {
804
+ }
805
+
806
+ class CreateTasksActivity extends Service2()("@kitman-sh/sdk/loop/CreateTasksActivity") {
807
+ }
808
+
809
+ class IntegrationBranchActivity extends Service2()("@kitman-sh/sdk/loop/IntegrationBranchActivity") {
810
+ }
811
+
812
+ class MergeChangeRequestActivity extends Service2()("@kitman-sh/sdk/loop/MergeChangeRequestActivity") {
813
+ }
814
+
815
+ class ReleaseActivity extends Service2()("@kitman-sh/sdk/loop/ReleaseActivity") {
816
+ }
817
+ var hostActivity = (name, kind, capability, success, execute) => takeStep(name, kind, capability, make3({ name: `${kind}/${name}`, success, error: StepFailed, execute }));
818
+ var changeRequest = (name, request) => hostActivity(name, "change_request", "change_request", ChangeRequestResult, gen(function* () {
819
+ return yield* (yield* ChangeRequestActivity).run(request, name);
820
+ }));
821
+ var writeBack = (name, request) => hostActivity(name, "write_back", "write_back", Void, gen(function* () {
822
+ return yield* (yield* WriteBackActivity).run(request, name);
823
+ }));
824
+ var artifact = (name, request) => hostActivity(name, "artifact", undefined, ArtifactResult, gen(function* () {
825
+ return yield* (yield* ArtifactActivity).run(request, name);
826
+ }));
827
+ var note = (name, request) => hostActivity(name, "note", undefined, Void, gen(function* () {
828
+ return yield* (yield* NoteActivity).run(request, name);
829
+ }));
830
+ var comment = (name, request) => hostActivity(name, "comment", "post_comment", Void, gen(function* () {
831
+ return yield* (yield* CommentActivity).run(request, name);
832
+ }));
833
+ var createTasks = (name, request) => hostActivity(name, "create_tasks", "create_tasks", CreateTasksResult, gen(function* () {
834
+ return yield* (yield* CreateTasksActivity).run(request, name);
835
+ }));
836
+ var integrationBranch = (name, request) => hostActivity(name, "integration_branch", "merge_change_request", IntegrationBranch, gen(function* () {
837
+ return yield* (yield* IntegrationBranchActivity).run(request, name);
838
+ }));
839
+ var mergeChangeRequest = (name, request) => hostActivity(name, "merge_change_request", "merge_change_request", MergeResult, gen(function* () {
840
+ return yield* (yield* MergeChangeRequestActivity).run(request, name);
841
+ }));
842
+ var release2 = (name, request) => hostActivity(name, "release", "publish_release", ReleaseResult, gen(function* () {
843
+ return yield* (yield* ReleaseActivity).run(request, name);
844
+ }));
845
+ // packages/sdk/src/loop/test-loop.ts
846
+ var LoopJournal = Struct({
847
+ activities: Record(String2, Json),
848
+ deferreds: Record(String2, Json)
849
+ });
850
+
851
+ class ScriptedFailure extends TaggedClass("ScriptedFailure") {
852
+ }
853
+ // packages/sdk/src/loop/review.ts
854
+ var Severity = Literals(["blocker", "major", "minor"]);
855
+ var Finding = Struct({
856
+ severity: Severity,
857
+ file: String2,
858
+ line: Int,
859
+ detail: String2
860
+ });
861
+ var MergedFinding = Struct({
862
+ id: String2,
863
+ ...Finding.fields,
864
+ seats: ArraySchema(String2)
865
+ });
866
+ var Rebuttal = Struct({ findingId: String2, reason: String2 });
867
+ var RebuttalVerdict = Struct({ findingId: String2, accepted: Boolean2 });
868
+ var ScopeJudgement = Struct({ met: Boolean2, unmet: ArraySchema(String2) });
869
+ var rank = { blocker: 0, major: 1, minor: 2 };
870
+ var isBlocking = (finding) => finding.severity !== "minor";
871
+ var mergeFindings = (bySeat) => {
872
+ const merged = new Map;
873
+ for (const [seat, findings] of Object.entries(bySeat))
874
+ for (const finding of findings) {
875
+ const id = `${finding.file}:${finding.line}`;
876
+ const known = merged.get(id);
877
+ const seats = [...new Set([...known?.seats ?? [], seat])];
878
+ const worst = known === undefined || rank[finding.severity] < rank[known.severity] ? finding : known;
879
+ merged.set(id, { id, severity: worst.severity, file: worst.file, line: worst.line, detail: worst.detail, seats });
880
+ }
881
+ return [...merged.values()].toSorted((left, right) => rank[left.severity] - rank[right.severity]);
882
+ };
883
+ var splitDisputed = (findings, rebuttals) => {
884
+ const disputed = [];
885
+ const undisputed = [];
886
+ for (const finding of findings) {
887
+ const rebuttal = rebuttals.find((entry) => entry.findingId === finding.id);
888
+ if (rebuttal === undefined)
889
+ undisputed.push(finding);
890
+ else
891
+ disputed.push({ finding, rebuttal });
892
+ }
893
+ return { disputed, undisputed };
894
+ };
895
+ var settleRound = (round) => {
896
+ const { disputed, undisputed } = splitDisputed(round.findings, round.rebuttals);
897
+ const accepted = (entry) => {
898
+ const verdicts = round.verdicts.filter((verdict) => verdict.findingId === entry.finding.id);
899
+ return verdicts.length > 0 && verdicts.every((verdict) => verdict.accepted);
900
+ };
901
+ return {
902
+ open: undisputed,
903
+ withdrawn: disputed.filter(accepted),
904
+ standing: disputed.filter((entry) => !accepted(entry))
905
+ };
906
+ };
907
+ var rallyStop = (input) => {
908
+ const open = input.settled.open.filter(isBlocking).map((finding) => finding.id);
909
+ const standing = input.settled.standing.flatMap((entry) => isBlocking(entry.finding) ? [entry.finding.id] : []);
910
+ const unsettled = [...open, ...standing];
911
+ const stop = (reason) => ({ stop: true, reason, unsettled });
912
+ if (unsettled.length === 0)
913
+ return stop("settled");
914
+ if (standing.length > 0)
915
+ return stop("dispute_stands");
916
+ if (input.previous !== undefined && sameIds(input.previous, unsettled))
917
+ return stop("findings_returned");
918
+ return input.round >= input.maxRounds ? stop("round_cap") : { stop: false };
919
+ };
920
+ var sameIds = (left, right) => left.length === right.length && left.every((id) => right.includes(id));
921
+ // packages/sdk/src/loop/check.ts
922
+ class CheckFailed extends TaggedError2()("CheckFailed", {
923
+ loop: String2,
924
+ check: String2,
925
+ reason: String2
926
+ }) {
927
+ get detail() {
928
+ return `Check "${this.check}": ${this.reason}`;
929
+ }
930
+ get message() {
931
+ return `Loop "${this.loop}": ${this.detail}`;
932
+ }
933
+ }
934
+
935
+ class StepNamedTwice extends TaggedError2()("StepNamedTwice", {
936
+ loop: String2,
937
+ check: String2,
938
+ step: String2
939
+ }) {
940
+ get detail() {
941
+ return `Check "${this.check}": Step "${this.step}" is named twice`;
942
+ }
943
+ get message() {
944
+ return `Loop "${this.loop}": ${this.detail}`;
945
+ }
946
+ }
947
+
948
+ class ReplayDiverged extends TaggedError2()("ReplayDiverged", {
949
+ loop: String2,
950
+ check: String2,
951
+ first: ArraySchema(String2),
952
+ replay: ArraySchema(String2),
953
+ rerun: ArraySchema(String2)
954
+ }) {
955
+ get detail() {
956
+ const steps = (names) => names.join(", ") || "no Steps";
957
+ 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.`;
958
+ }
959
+ get message() {
960
+ return `Loop "${this.loop}": ${this.detail}`;
961
+ }
962
+ }
963
+ var LoopCheckError = Union([CheckFailed, StepNamedTwice, ReplayDiverged]);
964
+ export { LoopOutcome, defineLoop, ManifestInvalid, make, Suspended, make2, await_, make3, evidenceGate, ChildFailed, agentWork, ask, call, waitFor, verify, PlanTickets, planWaves, ChangeRequestResult, CreateTasksResult, changeRequest, writeBack, artifact, note, comment, createTasks, integrationBranch, mergeChangeRequest, release2, Finding, MergedFinding, Rebuttal, RebuttalVerdict, ScopeJudgement, isBlocking, mergeFindings, settleRound, rallyStop, LoopCheckError };