wicked-crew 0.7.14 → 0.7.16

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.
@@ -156,13 +156,13 @@ export declare function prUrlFrom(text: string): string | null;
156
156
  */
157
157
  export declare function deliverUnitOf(view: SessionView): WorkUnit | null;
158
158
  /**
159
- * Is this a `failed` run whose ONLY failure was the deliver phase's LIFT collision (crew#418)?
159
+ * Is this a `failed` run whose ONLY failure was a recoverable deliver LIFT failure (crew#418/#432)?
160
160
  *
161
161
  * The deliver phase is the LAST phase, so a rejected deliver unit whose `denial_reason` carries
162
162
  * the deliver script's {@link DELIVER_LIFT_CONFLICT_MARKER} — with EVERY non-deliver unit still
163
163
  * `done` — means the run's WORK is complete and committed on its `wicked/<id>` branch: only the
164
- * lift into origin collided (a rebase conflict the changelog union merge could not clear, or a
165
- * non-fast-forward push). The engine reports the run `failed` because a Tool phase exited
164
+ * lift into origin could not complete (a rebase conflict the changelog union merge could not
165
+ * clear, a non-fast-forward push, or a transport/auth/remote rejection). The engine reports the run `failed` because a Tool phase exited
166
166
  * non-zero; crew reinterprets THIS shape on the wire as `completed` + `delivery: 'stranded'`
167
167
  * (recoverable via `POST /runs/:id/deliver`) — the same wire-derivation posture as `delivery`
168
168
  * itself, leaving the engine's durable `failed` record untouched. The deliver unit stays
@@ -271,13 +271,13 @@ export function deliverUnitOf(view) {
271
271
  return view.units.find((u) => (u.tool_cmd ?? []).join(' ').includes('gh pr create')) ?? null;
272
272
  }
273
273
  /**
274
- * Is this a `failed` run whose ONLY failure was the deliver phase's LIFT collision (crew#418)?
274
+ * Is this a `failed` run whose ONLY failure was a recoverable deliver LIFT failure (crew#418/#432)?
275
275
  *
276
276
  * The deliver phase is the LAST phase, so a rejected deliver unit whose `denial_reason` carries
277
277
  * the deliver script's {@link DELIVER_LIFT_CONFLICT_MARKER} — with EVERY non-deliver unit still
278
278
  * `done` — means the run's WORK is complete and committed on its `wicked/<id>` branch: only the
279
- * lift into origin collided (a rebase conflict the changelog union merge could not clear, or a
280
- * non-fast-forward push). The engine reports the run `failed` because a Tool phase exited
279
+ * lift into origin could not complete (a rebase conflict the changelog union merge could not
280
+ * clear, a non-fast-forward push, or a transport/auth/remote rejection). The engine reports the run `failed` because a Tool phase exited
281
281
  * non-zero; crew reinterprets THIS shape on the wire as `completed` + `delivery: 'stranded'`
282
282
  * (recoverable via `POST /runs/:id/deliver`) — the same wire-derivation posture as `delivery`
283
283
  * itself, leaving the engine's durable `failed` record untouched. The deliver unit stays
@@ -1 +1 @@
1
- {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/api/routes.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/api/routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAgB,MAAM,SAAS,CAAC;AAC7D,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAOxB,OAAO,EAAmD,WAAW,EAA4E,MAAM,oBAAoB,CAAC;AAG5K,OAAO,EAAiB,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAChE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAMnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAWrD,OAAO,EAAyB,KAAK,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAYtF,OAAO,EAAe,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AAGnF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAGzE,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAOL,KAAK,SAAS,EACf,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EACL,aAAa,EAOd,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAC;AAC9D,OAAO,EAGL,KAAK,WAAW,EAEhB,KAAK,qBAAqB,EAC3B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAe,KAAK,QAAQ,EAAE,MAAM,WAAW,CAAC;AAGvD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAgG7C;;;;;;;;;;;;GAYG;AAIH,eAAO,MAAM,YAAY;;;;;;;;IAQvB;+FAC2F;;IAE3F;;;;;;+CAM2C;;IAE3C;;0FAEsF;;IAEtF;;;;6FAIyF;;IAEzF;;wDAEoD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EASpD,CAAC;AAEH,eAAO,MAAM,UAAU;;;;;;;;;EAGZ,CAAC;AAEZ;;yEAEyE;AACzE,eAAO,MAAM,cAAc;;;;;;EAEhB,CAAC;AAgBZ,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;EAQpB,CAAC;AAOZ,4FAA4F;AAC5F,eAAO,MAAM,cAAc;;;;;;;;;EAGhB,CAAC;AAwBZ,sEAAsE;AACtE,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,QAAQ,CAAC;IAChB,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAED;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B,UAAU,CAAC,EAAE,iBAAiB,CAAC;IAC/B;oGACgG;IAChG,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB;;sDAEkD;IAClD,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB;uGACmG;IACnG,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B;;qBAEiB;IACjB,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B;;4DAEwD;IACxD,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IAC3C;;oGAEgG;IAChG,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACrD;;;yBAGqB;IACrB,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACxE;;;;gGAI4F;IAC5F,aAAa,CAAC,EAAE,uBAAuB,CAAC;IACxC;;2FAEuF;IACvF,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B;;wGAEoG;IACpG,mBAAmB,CAAC,EAAE,qBAAqB,CAAC;IAC5C,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C;2FACuF;IACvF,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,gBAAgB,CAAC,EAAE,MAAM,KAAK,OAAO,GAAG,IAAI,CAAC;IAC1E;;0DAEsD;IACtD,kBAAkB,CAAC,EAAE,qBAAqB,CAAC;IAC3C;;gFAE4E;IAC5E,iBAAiB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,cAAc,CAAC;IAC3D;4FACwF;IACxF,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB;mGAC+F;IAC/F,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,eAAe,EACpB,OAAO,EAAE,WAAW,EACpB,SAAS,EAAE,SAAS,EACpB,gBAAgB,EAAE,gBAAgB,EAIlC,YAAY,GAAE,WAA+B,EAG7C,QAAQ,GAAE,iBAAqF,EAK/F,QAAQ,GAAE,YAA0D,EAGpE,OAAO,GAAE,WAAgB,GACxB,IAAI,CAmhFN"}
@@ -7,6 +7,7 @@ import { isAbsolute, join, relative, resolve } from 'node:path';
7
7
  import { fileURLToPath } from 'node:url';
8
8
  import { CampaignsUnsupportedError, ChatUnsupportedError, CoreAdapter, ElicitationUnsupportedError, SteeringUnsupportedError, humanGatePhaseIds } from '../core/adapter.js';
9
9
  import { codeGraphDb, requirementsGraph } from '../core/repoPaths.js';
10
+ import { resolveCursorUnit } from '../core/cursor.js';
10
11
  import { detectRefusal } from './gate-cache.js';
11
12
  import { QeGateCache } from '../qe/gate-events.js';
12
13
  import { buildAcceptanceView, resolveRunWorkflow } from '../qe/acceptance.js';
@@ -188,6 +189,11 @@ const InjectSchema = z.object({
188
189
  /** `"all"` broadcasts to every active worker; any other value is a CLI key. */
189
190
  target: z.string().min(1).default('all'),
190
191
  }).strict();
192
+ // The manual reassign lever (crew#442): `cli` omitted lets the engine's council re-pick, the
193
+ // same shape the automatic stall-watchdog escalation uses for an unknown failover target.
194
+ const ReassignSchema = z.object({
195
+ cli: z.string().min(1).optional(),
196
+ }).strict();
191
197
  export const OpenTerminalSchema = z.object({
192
198
  cwd: z.string().min(1),
193
199
  cmd: z.array(z.string().min(1)).min(1).optional(),
@@ -293,8 +299,8 @@ runtime = {}) {
293
299
  // tick on a miss, so the list fan-out never spawns git.
294
300
  // Applied at DTO assembly on exactly the two endpoints that serve the run DTO
295
301
  // (GET /runs + GET /runs/:id); the internal sessionsDetail() consumers are untouched.
296
- // crew#418 A: a `failed` run whose ONLY failure was the deliver phase's LIFT collision (a
297
- // rebase conflict the changelog union merge could not clear, or a non-fast-forward push) is
302
+ // crew#418/#432: a `failed` run whose ONLY failure was a recoverable deliver LIFT failure (a
303
+ // rebase conflict, non-fast-forward, or auth/transport/remote push rejection) is
298
304
  // reinterpreted on the wire as `completed` + `delivery: 'stranded'` — recoverable, not a hard
299
305
  // failure. The engine's durable record stays `failed` (audit trail); this is a wire derivation,
300
306
  // exactly like `delivery` itself, applied at the SAME three terminal-status decision points so
@@ -1036,7 +1042,7 @@ runtime = {}) {
1036
1042
  const run = views.find((v) => v.session.id === id);
1037
1043
  if (!run)
1038
1044
  return reply.code(404).send({ error: 'Run not found' });
1039
- // crew#418 A: a run stranded by a deliver-phase lift collision reads `failed` from the
1045
+ // crew#418/#432: a run stranded by a recoverable deliver lift failure reads `failed` from the
1040
1046
  // engine but IS liftable post-hoc — normalize its status to `completed` so this route
1041
1047
  // accepts it, exactly as the run wire and the resume route see it.
1042
1048
  const conflictStrand = normalizeStranded(run);
@@ -1067,7 +1073,7 @@ runtime = {}) {
1067
1073
  }
1068
1074
  deliverInFlight.add(id);
1069
1075
  // The worktree the script runs in. Usually the run's own; but the engine REAPS a
1070
- // failed-deliver run's worktree once its work is committed (crew#418) — the work then lives
1076
+ // failed-deliver run's worktree once its work is committed (crew#418/#432) — the work then lives
1071
1077
  // on the `wicked/<id>` branch. For such a strand, stand a throwaway worktree back up from
1072
1078
  // that branch and lift THAT; the branch (the record) is untouched. `cleanupWorktree` tears
1073
1079
  // the throwaway down after the lift.
@@ -1562,6 +1568,49 @@ runtime = {}) {
1562
1568
  return reply.code(409).send({ error: message(err) });
1563
1569
  }
1564
1570
  });
1571
+ // The manual operator lever (crew#442): recycles a run's CURSOR unit via the same
1572
+ // `adapter.reassignUnit` path the stall-watchdog's automatic escalation uses, for when a
1573
+ // wedged unit needs recovering and auto-escalation is off, exhausted, or itself failed. Scoped
1574
+ // to `executing` runs only — the same scope the automatic ladder acts within, since only an
1575
+ // executing run has a cursor unit to reassign.
1576
+ app.post(`${V}/runs/:id/reassign`, { config: { manifest: { requestType: 'ReassignRequest', statusCodes: [200, 400, 404, 409] } } }, async (req, reply) => {
1577
+ const { id } = req.params;
1578
+ const parsed = ReassignSchema.safeParse(req.body ?? {});
1579
+ if (!parsed.success) {
1580
+ return reply.code(400).send(invalidBody(parsed.error, 'Invalid request body'));
1581
+ }
1582
+ const views = await adapter.sessionsDetail();
1583
+ const run = views.find((v) => v.session.id === id);
1584
+ if (!run)
1585
+ return reply.code(404).send({ error: 'Run not found' });
1586
+ if (run.session.status !== 'executing') {
1587
+ return reply.code(409).send({
1588
+ error: `run ${id} is ${run.session.status}, not executing — only an executing run has a cursor unit to reassign`,
1589
+ });
1590
+ }
1591
+ const requestedCli = parsed.data.cli;
1592
+ if (requestedCli !== undefined) {
1593
+ const pool = Array.isArray(run.session.clis) ? run.session.clis : [];
1594
+ if (!pool.includes(requestedCli)) {
1595
+ return reply.code(400).send({
1596
+ error: `cli "${requestedCli}" is not in this run's seat pool (${pool.join(', ') || 'none known'})`,
1597
+ });
1598
+ }
1599
+ }
1600
+ const cursor = resolveCursorUnit(run);
1601
+ const ord = cursor?.ord ?? run.session.unit_ix;
1602
+ try {
1603
+ await adapter.reassignUnit(id, ord, requestedCli ?? null);
1604
+ audit.record('run.reassigned', actorOf(req), {
1605
+ runId: id,
1606
+ detail: { ord, ...(requestedCli !== undefined ? { cli: requestedCli } : {}) },
1607
+ });
1608
+ return reply.send({ status: 'ok', ord, ...(requestedCli !== undefined ? { cli: requestedCli } : {}) });
1609
+ }
1610
+ catch (err) {
1611
+ return reply.code(409).send({ error: message(err) });
1612
+ }
1613
+ });
1565
1614
  // The gate prompt for a paused run, so a fresh browser can render the gate after a late join.
1566
1615
  //
1567
1616
  // Cache first, durable event log second (FINDING-051). The cache is process-lifetime, so before