agent-dag 1.35.2 → 1.35.3

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.
@@ -40,7 +40,7 @@
40
40
  document.documentElement.setAttribute("data-theme", stored === "light" ? "light" : "dark");
41
41
  })();
42
42
  </script>
43
- <script type="module" crossorigin src="/assets/index-B4-a3WNi.js"></script>
43
+ <script type="module" crossorigin src="/assets/index-DkpFbk1G.js"></script>
44
44
  <link rel="stylesheet" crossorigin href="/assets/index-FKxgHN0p.css">
45
45
  </head>
46
46
  <body>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-dag",
3
- "version": "1.35.2",
3
+ "version": "1.35.3",
4
4
  "description": "Live deck of Claude Code and Codex agents — watch parallel subagents fork, call tools, and return on one calm canvas. Also available as npx ccdeck and npx agent-dag.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -788,7 +788,9 @@ function maybeResolveCodex(payload) {
788
788
  // event_msg/user_message → UserPromptSubmit (Codex ≤ 0.144)
789
789
  // event_msg/item_completed/UserMessage → UserPromptSubmit (Codex ≥ 0.147)
790
790
  // response_item/function_call → PreToolUse
791
- // response_item/function_call_output → PostToolUse
791
+ // response_item/function_call_output → PostToolUse / PostToolUseFailure,
792
+ // decided by the outcome line Codex
793
+ // prepends to the output (codexCallFailed)
792
794
  // event_msg/token_count → UsageObserved
793
795
  // event_msg/task_started (+window) → ModelObserved (context window)
794
796
  // event_msg/task_complete → Stop (the turn finished)
@@ -989,14 +991,92 @@ export function codexObjToPayload(obj, sid, cwd) {
989
991
  if (pl.type === "custom_tool_call") {
990
992
  return { ...base, hook_event_name: "PreToolUse", tool_name: pl.name ?? "tool", tool_input: { patch: pl.input }, tool_use_id: pl.call_id, model };
991
993
  }
994
+ // #397: the outcome, not just the fact that an outcome arrived. This used
995
+ // to hardcode "PostToolUse" for both output types, and the reducer derives
996
+ // `ok` from the event NAME (`tc.ok = name === "PostToolUse"`) — so `ok` was
997
+ // structurally incapable of being false on the Codex path and a command
998
+ // that exited non-zero drew exactly like one that succeeded. Every surface
999
+ // that reads the flag inherited the lie: the burst dot, the tool row, the
1000
+ // ToolModal styling, the detail-panel error count, and the session
1001
+ // summary's "Errors" stat, which was therefore pinned at 0 for the life of
1002
+ // a Codex session. `PostToolUseFailure` is the name the reducer already
1003
+ // understands (it sets `ok = false` and writes an `errorPreview` from the
1004
+ // response); nothing but this mapper was missing.
992
1005
  if (pl.type === "function_call_output" || pl.type === "custom_tool_call_output") {
993
1006
  const tool_response = pl.output != null ? parseCodexOutput(pl.output) : undefined;
994
- return { ...base, hook_event_name: "PostToolUse", tool_use_id: pl.call_id, tool_response, model };
1007
+ const name = codexCallFailed(pl.output) ? "PostToolUseFailure" : "PostToolUse";
1008
+ return { ...base, hook_event_name: name, tool_use_id: pl.call_id, tool_response, model };
995
1009
  }
996
1010
  }
997
1011
  return null;
998
1012
  }
999
1013
 
1014
+ /**
1015
+ * The text parts of a Codex tool result, in the order Codex wrote them.
1016
+ *
1017
+ * Codex writes the result in two different containers and the deck sees both,
1018
+ * so this is where the difference stops. Across the rollouts sampled here:
1019
+ * `custom_tool_call_output.output` is an ARRAY of `{ type: "input_text", text }`
1020
+ * parts (85/85, on 0.144 and 0.147 alike), and `function_call_output.output` is
1021
+ * a bare string (32/32). The `{ output, metadata }` envelope `parseCodexOutput`
1022
+ * unwraps was written by neither, but it is cheap to keep tolerating and the
1023
+ * unwrapping already lives there, so the string case is routed through it
1024
+ * rather than duplicating the guess.
1025
+ */
1026
+ function codexOutputParts(output) {
1027
+ if (output == null) return [];
1028
+ if (Array.isArray(output)) {
1029
+ return output.map(p => (p && typeof p.text === "string" ? p.text : ""));
1030
+ }
1031
+ const unwrapped = parseCodexOutput(output);
1032
+ return typeof unwrapped === "string" ? [unwrapped] : [];
1033
+ }
1034
+
1035
+ /**
1036
+ * Did this Codex tool call actually fail?
1037
+ *
1038
+ * Codex prepends its own wrapper line to the tool's output and that line — not
1039
+ * any structured field — is where the outcome lives. Verified against every
1040
+ * tool result in this machine's CODEX_HOME:
1041
+ *
1042
+ * 0.144.5 exec "Script completed" 75 "Script failed" 2
1043
+ * 0.147.0 exec "Script completed" 6 (no failure observed)
1044
+ * 0.144.5 apply_patch "Exit code: 0" 2
1045
+ * 0.144.5 exec_command / run — bare string, no wrapper line at all 32
1046
+ *
1047
+ * The two CLI versions spell it IDENTICALLY, which is why one rule covers both
1048
+ * and why this needs no version sniffing: 0.147 renamed the prompt event (see
1049
+ * the `item_completed` branch above) but left the exec wrapper alone.
1050
+ *
1051
+ * Only the FIRST part's FIRST line is read, and that precision is load-bearing
1052
+ * rather than tidiness. The wrapper line is at part index 0 in 85 of 85 results
1053
+ * that have one; the later parts are the command's own stdout, and the command
1054
+ * prints whatever it likes there. On this machine two exec results contain a
1055
+ * line reading "Script error:" in part 1 — output from a script that ran fine
1056
+ * under a wrapper that says "Script completed" — so a rule that scanned every
1057
+ * part would paint two successful calls red. `\r` is stripped because the same
1058
+ * wrapper is written by Codex on Windows.
1059
+ *
1060
+ * Silence means success, deliberately. A result with no wrapper line — every
1061
+ * `function_call_output` on 0.144, and whatever container a future Codex
1062
+ * invents — keeps today's behaviour of mapping to `PostToolUse`. Reporting an
1063
+ * unknown outcome as a failure would trade one wrong colour for another, and
1064
+ * this direction is the recoverable one: a missed failure is a call that draws
1065
+ * as it always has, while a false failure puts a red dot and an "Errors" count
1066
+ * on a session that did nothing wrong.
1067
+ */
1068
+ function codexCallFailed(output) {
1069
+ const first = codexOutputParts(output)[0];
1070
+ if (typeof first !== "string") return false;
1071
+ const head = first.split("\n")[0].replace(/\r$/, "");
1072
+ if (/^Script failed\b/.test(head)) return true;
1073
+ // apply_patch reports itself with an exit code instead of a word. Anything
1074
+ // non-zero is a patch that did not apply.
1075
+ const exit = /^Exit code:\s*(\d+)/.exec(head);
1076
+ if (exit) return Number(exit[1]) !== 0;
1077
+ return false;
1078
+ }
1079
+
1000
1080
  function parseCodexOutput(raw) {
1001
1081
  if (typeof raw !== "string") return raw;
1002
1082
  try {