@higherdev/cli 0.27.0 → 0.28.0

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/tui/App.js CHANGED
@@ -425,7 +425,7 @@ export function App({ initial, availableUpdate: initialUpdate = null, updateDeps
425
425
  activity: activity.lines,
426
426
  },
427
427
  }));
428
- if (followShouldStop(follow.run, follow.reply)) {
428
+ if (followShouldStop(follow.run, follow.reply, follow.tagged)) {
429
429
  const settled = settleChatReply(follow.reply, follow.run);
430
430
  setThread(key, (current) => ({
431
431
  ...current,
@@ -91,10 +91,16 @@ export function pendingActivity(events, run, label, now = Date.now()) {
91
91
  lines: narrateEvents(events).map((line) => line.title),
92
92
  };
93
93
  }
94
- export function followShouldStop(run, reply) {
94
+ export function followShouldStop(run, reply, tagged = false) {
95
95
  if (reply)
96
96
  return true;
97
- if (run && ["failed", "killed"].includes(run.status))
97
+ if (!run)
98
+ return false;
99
+ if (["failed", "killed"].includes(run.status))
100
+ return true;
101
+ // The role's other runs may finish while ours is still queued; only the run
102
+ // started for this message is definitive when it ends without a reply.
103
+ if (tagged && !["queued", "running"].includes(run.status))
98
104
  return true;
99
105
  return false;
100
106
  }
@@ -15,6 +15,12 @@ export function failedChatNote(reason) {
15
15
  const detail = reason?.trim();
16
16
  return detail ? `${NO_REPLY_NOTE} ${detail}` : NO_REPLY_NOTE;
17
17
  }
18
+ /** A run that finished without writing a reply message: show what it did instead. */
19
+ export const NO_REPLY_WRITTEN = "Finished without a reply.";
20
+ export function finishedWithoutReplyNote(summary) {
21
+ const detail = summary?.trim();
22
+ return detail ? `${NO_REPLY_WRITTEN} ${detail}` : NO_REPLY_WRITTEN;
23
+ }
18
24
  export function answeredIn(ms) {
19
25
  return `answered in ${Math.max(0, Math.round(ms / 1000))}s`;
20
26
  }
@@ -25,5 +31,9 @@ export function settleChatReply(reply, run) {
25
31
  if (run && ["failed", "killed"].includes(run.status ?? "")) {
26
32
  return { body: failedChatNote(run.summary), pending: false, steps: [], done: true, replyMs: run.reply_ms ?? null };
27
33
  }
34
+ if (run && run.status && !["queued", "running"].includes(run.status)) {
35
+ return { body: finishedWithoutReplyNote(run.summary), pending: false, steps: [], done: true,
36
+ replyMs: run.reply_ms ?? null };
37
+ }
28
38
  return { body: "", pending: true, steps: [], done: false, replyMs: null };
29
39
  }
package/dist/tui/data.js CHANGED
@@ -156,7 +156,7 @@ export async function followChat(config, role, messageId, since) {
156
156
  const reply = messages.find((message) => message.from_role === role
157
157
  && ["human", "operator", "all"].includes(message.to_role)
158
158
  && (!run || !message.run_id || message.run_id === run.id));
159
- return { run, events, reply: reply?.body_md ?? null };
159
+ return { run, events, reply: reply?.body_md ?? null, tagged: Boolean(tagged) };
160
160
  }
161
161
  export async function loadTicketDetail(config, key) {
162
162
  const { ticket, pr, events, runs, messages, decisions, attachments } = await showTicket(key, config);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@higherdev/cli",
3
- "version": "0.27.0",
3
+ "version": "0.28.0",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",