squadrant 0.19.4 → 0.19.5

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.
@@ -887,6 +887,11 @@ function reduce(rec, ev, now) {
887
887
  return stampAttempt(base, { resumeRef: ev.resumeRef }, now);
888
888
  case "task.turn.started":
889
889
  return { ...stampAttempt(base, {}, now), state: "working", pendingTool: void 0, pendingMonitor: void 0 };
890
+ case "task.turn.failed":
891
+ // #763: a crew's turn died on an API error (StopFailure hook). Anti-#2576:
892
+ // NOT task.failed — a hook may never terminalize a task. Falls through to
893
+ // the exact same turn-boundary transition as task.turn.completed below;
894
+ // only the notify message (reduce.ts formatMessage) differs.
890
895
  case "task.turn.completed":
891
896
  if (isStickyAttention(rec.state))
892
897
  return { ...rec, lastHeartbeat: now, lastEvent: ev.type };
@@ -1002,6 +1007,9 @@ function formatMessage(rec, event) {
1002
1007
  return `CREW STALLED ${tag}: no heartbeat in ${rec.heartbeatBudgetMs}ms`;
1003
1008
  }
1004
1009
  case "awaiting-input":
1010
+ if (event?.type === "task.turn.failed") {
1011
+ return `CREW TURN FAILED ${tag}: API error ended the turn (not a stall) \u2014 ${event.error}`;
1012
+ }
1005
1013
  return `CREW IDLE ${tag}: turn ended, awaiting your reply.`;
1006
1014
  default:
1007
1015
  return null;
@@ -1411,6 +1419,7 @@ var init_reduce = __esm({
1411
1419
  "task.session",
1412
1420
  "task.turn.started",
1413
1421
  "task.turn.completed",
1422
+ "task.turn.failed",
1414
1423
  "task.delta",
1415
1424
  "task.input.requested",
1416
1425
  "task.approval.requested",
@@ -7997,7 +8006,7 @@ import { execSync as execSync6 } from "child_process";
7997
8006
  import { readFileSync as readFileSync10 } from "fs";
7998
8007
  import { homedir as homedir8 } from "os";
7999
8008
  import { join as join15 } from "path";
8000
- var nextAskUserQuestionRequestId = Date.now();
8009
+ var nextHookRequestId = Date.now();
8001
8010
 
8002
8011
  // packages/agents/dist/headless/types.js
8003
8012
  var HEADLESS_ERROR_TAIL = 2e3;
@@ -9703,7 +9712,13 @@ var CLAUDE_HOOK_EVENTS = [
9703
9712
  ["Stop", "stop"],
9704
9713
  ["Notification", "notification"],
9705
9714
  ["PreToolUse", "ask-question", "AskUserQuestion"],
9706
- ["SessionEnd", "session-end"]
9715
+ ["SessionEnd", "session-end"],
9716
+ // #760: fires ~6s before the matching Notification, carrying tool_name +
9717
+ // tool_input directly — a strictly better task.blocked source.
9718
+ ["PermissionRequest", "permission-request"],
9719
+ // #763: the turn died on an API error — today squadrant has no source for
9720
+ // this at all; without it the watchdog reports a plain stall (wrong story).
9721
+ ["StopFailure", "stop-failure"]
9707
9722
  ];
9708
9723
  var DEFAULT_HOOK_CMD = "squadrant hooks";
9709
9724
  function installClaudeHooks(opts = {}) {
@@ -9781,6 +9796,10 @@ function mapSubToLifecycle(sub) {
9781
9796
  return "needsInput";
9782
9797
  case "ask-question":
9783
9798
  return "needsInput";
9799
+ case "permission-request":
9800
+ return "needsInput";
9801
+ case "stop-failure":
9802
+ return "idle";
9784
9803
  case "session-end":
9785
9804
  return "session-end";
9786
9805
  default: