@kitman-sh/software-engineering 0.10.63 → 0.10.64

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/bundle.js CHANGED
@@ -21276,6 +21276,7 @@ var shepherd_default = defineLoop({
21276
21276
  let unreviewed;
21277
21277
  let notCarried;
21278
21278
  let behind = false;
21279
+ let pushed;
21279
21280
  const done = (status, reason) => ({ status, reason, fixRounds, replies });
21280
21281
  const runOnRunner = (step, cycle, head, checks) => gen2(function* () {
21281
21282
  const verification = `pipeline-${step}:${cycle}`;
@@ -21302,6 +21303,18 @@ var shepherd_default = defineLoop({
21302
21303
  return done("needs_you", `Stopped after ${cycle - 1} looks without landing it`);
21303
21304
  }
21304
21305
  const pipeline = yield* pipelineStatus(`pipeline:${cycle}`, { changeRequestId });
21306
+ if (pushed !== undefined && pipeline.head !== pushed.head) {
21307
+ if (++pushed.stale > 5)
21308
+ return done("needs_you", `The forge still shows ${pipeline.head}, not ${pushed.head} that the catch-up pushed`);
21309
+ yield* waitFor(`pushed-again:${cycle}`, {
21310
+ event: "change_request.mergeable",
21311
+ filter: { changeRequestId, head: pushed.head },
21312
+ timeout: "1 minute",
21313
+ ...pipeline.readAt === undefined ? undefined : { since: pipeline.readAt }
21314
+ }).pipe(catchTag2("WaitTimedOut", () => void_3));
21315
+ continue;
21316
+ }
21317
+ pushed = undefined;
21305
21318
  if (pipeline.status === "none" && pipeline.runnerChecks !== undefined) {
21306
21319
  if (ranOnRunner.has(pipeline.head))
21307
21320
  return done("needs_you", `The pipeline ran on the Runner at ${pipeline.head}, but no result was recorded`);
@@ -21416,6 +21429,14 @@ var shepherd_default = defineLoop({
21416
21429
  if (!carried.approved)
21417
21430
  notCarried = `the approval was not carried: ${carried.reason}`;
21418
21431
  }
21432
+ if (caught !== undefined) {
21433
+ pushed = { head: caught.head, stale: 0 };
21434
+ yield* waitFor(`pushed:${cycle}`, {
21435
+ event: "change_request.mergeable",
21436
+ filter: { changeRequestId, head: caught.head },
21437
+ timeout: "5 minutes"
21438
+ }).pipe(catchTag2("WaitTimedOut", () => void_3));
21439
+ }
21419
21440
  }
21420
21441
  continue;
21421
21442
  }
@@ -29400,4 +29421,4 @@ var runKit = (config, identity, packages) => {
29400
29421
  runMain2(program.pipe(flatMap3((code) => sync2(() => process.exit(code)))));
29401
29422
  };
29402
29423
  // .kitman-build-entry.ts
29403
- runKit(kitman_config_default, { name: "@kitman-sh/software-engineering", version: "0.10.63" }, []);
29424
+ runKit(kitman_config_default, { name: "@kitman-sh/software-engineering", version: "0.10.64" }, []);
@@ -3187,7 +3187,7 @@
3187
3187
  "carried": [
3188
3188
  {
3189
3189
  "name": "@kitman-sh/software-engineering",
3190
- "version": "0.10.63",
3190
+ "version": "0.10.64",
3191
3191
  "setup": "2a237548a69b0cd53ec3be7f687cfa8c2128335b3a655d34e185f2abce6a3c37",
3192
3192
  "loops": [
3193
3193
  "build",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kitman-sh/software-engineering",
3
- "version": "0.10.63",
3
+ "version": "0.10.64",
4
4
  "description": "Everything for building software: Loops, their Agents, the skills they use and the Ponytail plugin.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",
@@ -17,12 +17,12 @@
17
17
  "tsconfig.json"
18
18
  ],
19
19
  "dependencies": {
20
- "@kitman-sh/sdk": "0.10.63",
20
+ "@kitman-sh/sdk": "0.10.64",
21
21
  "effect": "4.1.2"
22
22
  },
23
23
  "kitman": {
24
24
  "bundle": "dist/bundle.js",
25
- "digest": "efe909036da3aa085622d40064095546ad06305a86cab3bfb194afd3c8664664",
25
+ "digest": "40b7583dc039ac44fcb3fecb31a804d16d80697264a7baeb0034bd95d96e08ec",
26
26
  "protocolVersion": 5,
27
27
  "declarations": "dist/declarations.json",
28
28
  "setup": {
package/src/shepherd.ts CHANGED
@@ -189,6 +189,8 @@ export default defineLoop({
189
189
  let notCarried: string | undefined
190
190
  // The last merge did not go in as the ChangeRequest is: its target moved on, or it conflicts.
191
191
  let behind = false
192
+ /** The head a catch-up merge pushed, until the forge shows it, and how many reads showed another. */
193
+ let pushed: { readonly head: string; stale: number } | undefined
192
194
 
193
195
  const done = (status: Output['status'], reason: string): Output => ({ status, reason, fixRounds, replies })
194
196
 
@@ -228,6 +230,28 @@ export default defineLoop({
228
230
 
229
231
  const pipeline = yield* pipelineStatus(`pipeline:${cycle}`, { changeRequestId })
230
232
 
233
+ // The forge can show an older head for a while after a catch-up push: nothing is gated on any head but the
234
+ // pushed one, so look again; a person's push on top of it stops it for them.
235
+ if (pushed !== undefined && pipeline.head !== pushed.head) {
236
+ if (++pushed.stale > 5)
237
+ return done(
238
+ 'needs_you',
239
+ `The forge still shows ${pipeline.head}, not ${pushed.head} that the catch-up pushed`
240
+ )
241
+
242
+ // Only an Event since this read settles it, so the one that settled the last wait does not end it at once.
243
+ yield* waitFor(`pushed-again:${cycle}`, {
244
+ event: 'change_request.mergeable',
245
+ filter: { changeRequestId, head: pushed.head },
246
+ timeout: '1 minute',
247
+ ...(pipeline.readAt === undefined ? undefined : { since: pipeline.readAt })
248
+ }).pipe(Effect.catchTag('WaitTimedOut', () => Effect.void))
249
+
250
+ continue
251
+ }
252
+
253
+ pushed = undefined
254
+
231
255
  // The forge runs no pipeline for this repository: its pipeline runs on a Runner and is reported to Kitman.
232
256
  if (pipeline.status === 'none' && pipeline.runnerChecks !== undefined) {
233
257
  if (ranOnRunner.has(pipeline.head))
@@ -388,6 +412,17 @@ export default defineLoop({
388
412
 
389
413
  if (!carried.approved) notCarried = `the approval was not carried: ${carried.reason}`
390
414
  }
415
+
416
+ // The forge can show the old head for a moment after the push; the next look reads it once it shows this one.
417
+ if (caught !== undefined) {
418
+ pushed = { head: caught.head, stale: 0 }
419
+
420
+ yield* waitFor(`pushed:${cycle}`, {
421
+ event: 'change_request.mergeable',
422
+ filter: { changeRequestId, head: caught.head },
423
+ timeout: '5 minutes'
424
+ }).pipe(Effect.catchTag('WaitTimedOut', () => Effect.void))
425
+ }
391
426
  }
392
427
 
393
428
  continue