agent-rooms 0.11.0 → 0.11.1

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.
Files changed (2) hide show
  1. package/dist/normalize.js +31 -16
  2. package/package.json +1 -1
package/dist/normalize.js CHANGED
@@ -40,6 +40,21 @@ export function createNormalizer(host, runId) {
40
40
  }
41
41
  return [ev];
42
42
  };
43
+ const finalize = (exitCode, forcedOutcome) => {
44
+ if (state.finished)
45
+ return null;
46
+ state.finished = true;
47
+ const outcome = forcedOutcome ?? (state.sawTurnFailed || exitCode !== 0 ? "failed" : "ok");
48
+ return next({
49
+ kind: "run_finished",
50
+ outcome,
51
+ summary: { actions: state.actions, files: state.files, commands: state.commands }
52
+ });
53
+ };
54
+ // The vendors' own terminal events end the RUN, not the process: codex exec can
55
+ // linger long after `turn.completed` (its card must not sit on "Working"), and
56
+ // claude emits a final `result` before exit. Process exit is only the fallback.
57
+ const done = (outcome) => finalize(outcome === "ok" ? 0 : 1, outcome);
43
58
  const mapLine = host === "codex" ? codexLine : claudeLine;
44
59
  return {
45
60
  start() {
@@ -57,7 +72,7 @@ export function createNormalizer(host, runId) {
57
72
  return [];
58
73
  }
59
74
  try {
60
- return mapLine(obj, state, next).flatMap((e) => emit(e));
75
+ return mapLine(obj, state, next, done).flatMap((e) => emit(e));
61
76
  }
62
77
  catch (error) {
63
78
  // Never crash the run on a weird event; surface it generically.
@@ -66,15 +81,9 @@ export function createNormalizer(host, runId) {
66
81
  }
67
82
  },
68
83
  finish(exitCode, forcedOutcome) {
69
- if (state.finished)
70
- return null;
71
- state.finished = true;
72
- const outcome = forcedOutcome ?? (state.sawTurnFailed || exitCode !== 0 ? "failed" : "ok");
73
- return next({
74
- kind: "run_finished",
75
- outcome,
76
- summary: { actions: state.actions, files: state.files, commands: state.commands }
77
- });
84
+ // Vendor terminal event already closed the run -> the process-exit call
85
+ // no-ops (finished guard) and never overwrites the vendor's outcome.
86
+ return finalize(exitCode, forcedOutcome);
78
87
  }
79
88
  };
80
89
  }
@@ -85,7 +94,7 @@ export function createNormalizer(host, runId) {
85
94
  // {"type":"assistant","message":{"content":[{"type":"text","text":…}|{"type":
86
95
  // "tool_use","id":…,"name":…,"input":{…}}]}} and {"type":"user","message":
87
96
  // {"content":[{"type":"tool_result","tool_use_id":…,"is_error":…}]}}.
88
- function claudeLine(obj, state, next) {
97
+ function claudeLine(obj, state, next, done) {
89
98
  const type = obj.type;
90
99
  if (type === "assistant" || type === "user") {
91
100
  const message = obj.message;
@@ -153,8 +162,9 @@ function claudeLine(obj, state, next) {
153
162
  return out;
154
163
  }
155
164
  if (type === "result") {
156
- // handled by finish(); the final text already streamed as assistant text
157
- return [];
165
+ // Claude's own terminal event — freeze the card now; the final text already
166
+ // streamed as assistant text. subtype "success" = ok, anything else failed.
167
+ return [done(obj.subtype === "success" ? "ok" : "failed")];
158
168
  }
159
169
  if (type === "system" || type === "rate_limit_event")
160
170
  return [];
@@ -164,13 +174,18 @@ function claudeLine(obj, state, next) {
164
174
  // item.* events with item.type ∈ agent_message | reasoning | command_execution |
165
175
  // file_change | todo_list | mcp_tool_call | web_search | error. Transient
166
176
  // "Reconnecting…" errors are non-fatal. turn.failed → failed outcome.
167
- function codexLine(obj, state, next) {
177
+ function codexLine(obj, state, next, done) {
168
178
  const type = String(obj.type ?? "");
169
- if (type === "thread.started" || type === "turn.started" || type === "turn.completed")
179
+ if (type === "thread.started" || type === "turn.started")
170
180
  return [];
181
+ if (type === "turn.completed") {
182
+ // codex's terminal event. The exec process can LINGER long after this (MCP
183
+ // keep-alive) — the card must freeze here, not at process exit.
184
+ return [done("ok")];
185
+ }
171
186
  if (type === "turn.failed") {
172
187
  state.sawTurnFailed = true;
173
- return [];
188
+ return [done("failed")];
174
189
  }
175
190
  if (type === "error") {
176
191
  const message = String(obj.message ?? "");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-rooms",
3
- "version": "0.11.0",
3
+ "version": "0.11.1",
4
4
  "description": "Companion listener for Agent Rooms. Pair a device, wire the MCP connector, and wake idle agents (Claude Code, Codex, OpenClaw, Hermes) on mentions and task assignments.",
5
5
  "keywords": [
6
6
  "agent-rooms",