@cat-factory/app 0.107.3 → 0.107.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.
@@ -1,5 +1,5 @@
1
1
  <script setup lang="ts">
2
- import type { AgentState } from '~/types/domain'
2
+ import type { AgentState, PipelineStep } from '~/types/domain'
3
3
  import { agentKindMeta } from '~/utils/catalog'
4
4
  import {
5
5
  subtaskIconClass,
@@ -63,6 +63,26 @@ const STATE_META: Record<AgentState, { color: string; icon: string }> = {
63
63
  done: { color: '#22c55e', icon: 'i-lucide-circle-check' },
64
64
  }
65
65
 
66
+ // A reviewer gate (requirements-review / clarity-review) folding answers or re-reviewing in
67
+ // the driver parks the step in `waiting_decision`, but it's actively doing background LLM
68
+ // work and needs no human — so it must read as working (a spinning loader) rather than the
69
+ // waiting-for-a-human question mark.
70
+ function backgroundReview(s: PipelineStep) {
71
+ return reviews.isBackground(s.agentKind, props.taskId)
72
+ }
73
+ /** The state visual for a step's trailing status icon: failed cross for a mid-flight step on
74
+ * a failed run, a spinning working loader for a reviewer gate mid background cycle, else the
75
+ * plain per-state accent. */
76
+ function stepVisual(s: PipelineStep) {
77
+ if (isFailedStep(s.state, runFailed.value)) return FAILED_STEP_META
78
+ if (backgroundReview(s)) return STATE_META.working
79
+ return STATE_META[s.state]
80
+ }
81
+ /** Whether that trailing icon should spin — a live `working` step or a background review. */
82
+ function stepSpinning(s: PipelineStep) {
83
+ return !runFailed.value && (s.state === 'working' || backgroundReview(s))
84
+ }
85
+
66
86
  // Same todo-status icons the bootstrap card uses, so a zoomed-in task reads the
67
87
  // same way as a zoomed-in bootstrap.
68
88
  const ITEM_ICON: Record<string, string> = {
@@ -106,16 +126,10 @@ const ITEM_ICON: Record<string, string> = {
106
126
  </span>
107
127
  <UIcon
108
128
  v-else
109
- :name="
110
- isFailedStep(s.state, runFailed) ? FAILED_STEP_META.icon : STATE_META[s.state].icon
111
- "
129
+ :name="stepVisual(s).icon"
112
130
  class="ms-auto h-2.5 w-2.5 shrink-0"
113
- :class="s.state === 'working' && !runFailed ? 'animate-spin' : ''"
114
- :style="{
115
- color: isFailedStep(s.state, runFailed)
116
- ? FAILED_STEP_META.color
117
- : STATE_META[s.state].color,
118
- }"
131
+ :class="stepSpinning(s) ? 'animate-spin' : ''"
132
+ :style="{ color: stepVisual(s).color }"
119
133
  />
120
134
  </button>
121
135
 
@@ -139,16 +139,31 @@ const companionByStep = computed(() => steps.value.map((s) => gateCompanionFor(s
139
139
  // its container caught mid cold-boot) must stop looking live — no spinner, no pulse,
140
140
  // no "spinning up container" phase.
141
141
  const runFailed = computed(() => props.instance.status === 'failed')
142
- /** A step that is genuinely, currently working (not a stale mid-flight step). */
143
- function liveWorking(state: AgentState) {
144
- return state === 'working' && !runFailed.value
142
+ /**
143
+ * A reviewer gate (requirements-review / clarity-review) folding the answers or
144
+ * re-reviewing in the durable driver: the step parks in `waiting_decision` but is actively
145
+ * doing background LLM work and needs NO human, so it must read as working (a spinning
146
+ * loader), not the waiting-for-a-human question mark.
147
+ */
148
+ function backgroundReview(s: PipelineStep) {
149
+ return reviews.isBackground(s.agentKind, props.instance.blockId)
150
+ }
151
+ /**
152
+ * A step that is genuinely, currently working (not a stale mid-flight step) — including a
153
+ * reviewer gate doing background fold/re-review work.
154
+ */
155
+ function liveWorking(s: PipelineStep) {
156
+ return (s.state === 'working' || backgroundReview(s)) && !runFailed.value
145
157
  }
146
158
  /**
147
159
  * The state visual (label/color/icon) for a step: a step left `working` when the run
148
- * failed reads as "Failed" with a red cross, not a frozen "Working" loader.
160
+ * failed reads as "Failed" with a red cross, not a frozen "Working" loader; a reviewer gate
161
+ * mid background cycle reads as "Working" (a spinning loader), not "Needs decision".
149
162
  */
150
- function stepVisual(state: AgentState) {
151
- return isFailedStep(state, runFailed.value) ? FAILED_STEP_META : STATE_META.value[state]
163
+ function stepVisual(s: PipelineStep) {
164
+ if (isFailedStep(s.state, runFailed.value)) return FAILED_STEP_META
165
+ if (backgroundReview(s)) return STATE_META.value.working
166
+ return STATE_META.value[s.state]
152
167
  }
153
168
 
154
169
  /** A step counts as fully complete only once its state is `done`. */
@@ -248,14 +263,14 @@ const ITEM_ICON: Record<string, string> = {
248
263
  <!-- rail node -->
249
264
  <span
250
265
  class="relative z-10 flex h-9 w-9 shrink-0 items-center justify-center rounded-full border-2 bg-slate-950"
251
- :class="liveWorking(s.state) ? 'step-active' : ''"
252
- :style="{ borderColor: stepVisual(s.state).color }"
266
+ :class="liveWorking(s) ? 'step-active' : ''"
267
+ :style="{ borderColor: stepVisual(s).color }"
253
268
  >
254
269
  <UIcon
255
- :name="stepVisual(s.state).icon"
270
+ :name="stepVisual(s).icon"
256
271
  class="h-4 w-4"
257
- :class="liveWorking(s.state) ? 'animate-spin' : ''"
258
- :style="{ color: stepVisual(s.state).color }"
272
+ :class="liveWorking(s) ? 'animate-spin' : ''"
273
+ :style="{ color: stepVisual(s).color }"
259
274
  />
260
275
  </span>
261
276
 
@@ -307,9 +322,9 @@ const ITEM_ICON: Record<string, string> = {
307
322
  </div>
308
323
  <span
309
324
  class="ms-auto shrink-0 text-[11px] font-medium"
310
- :style="{ color: stepVisual(s.state).color }"
325
+ :style="{ color: stepVisual(s).color }"
311
326
  >
312
- {{ stepVisual(s.state).label }}
327
+ {{ stepVisual(s).label }}
313
328
  </span>
314
329
 
315
330
  <!-- restart-from-here: revealed on row hover, arms a two-click confirm
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cat-factory/app",
3
- "version": "0.107.3",
3
+ "version": "0.107.5",
4
4
  "description": "Reusable Nuxt layer for the Agent Architecture Board SPA (components, stores, composables, pages). Consume it from a thin deployment app via `extends: ['@cat-factory/app']` and point it at your backend with NUXT_PUBLIC_API_BASE. See deploy/frontend for an example.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -34,7 +34,7 @@
34
34
  "valibot": "^1.4.2",
35
35
  "vue": "3.5.39",
36
36
  "wretch": "^3.0.9",
37
- "@cat-factory/contracts": "0.117.0"
37
+ "@cat-factory/contracts": "0.118.0"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@toad-contracts/testing": "0.3.2",