@cat-factory/app 0.47.7 → 0.47.9

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.
@@ -4,6 +4,7 @@
4
4
  // • invalid pipelines (unknown agent kind / bad shape) — DELETE a custom one, RESEED a built-in;
5
5
  // • outdated built-ins (a newer catalog definition is available) — RESEED to adopt it.
6
6
  // Detection is client-side (see usePipelineHealth); the actions hit the pipelines store.
7
+ const { t } = useI18n()
7
8
  const ui = useUiStore()
8
9
  const pipelines = usePipelinesStore()
9
10
  const { invalid, outdated, hasIssues } = usePipelineHealth()
@@ -39,9 +40,10 @@ async function run(id: string, action: () => Promise<unknown>, failTitle: string
39
40
  }
40
41
  }
41
42
 
42
- const reseed = (id: string) => run(id, () => pipelines.reseed(id), 'Could not reseed pipeline')
43
+ const reseed = (id: string) =>
44
+ run(id, () => pipelines.reseed(id), t('pipeline.health.toast.reseedFailed'))
43
45
  const remove = (id: string) =>
44
- run(id, () => pipelines.removePipeline(id), 'Could not delete pipeline')
46
+ run(id, () => pipelines.removePipeline(id), t('pipeline.health.toast.deleteFailed'))
45
47
 
46
48
  /** Reseed every reseedable pipeline (outdated built-ins + invalid built-ins) in one go. */
47
49
  async function reseedAll() {
@@ -61,11 +63,11 @@ const reseedableCount = computed(
61
63
  </script>
62
64
 
63
65
  <template>
64
- <UModal v-model:open="open" title="Pipeline health" :ui="{ content: 'max-w-2xl' }">
66
+ <UModal v-model:open="open" :title="t('pipeline.health.title')" :ui="{ content: 'max-w-2xl' }">
65
67
  <template #body>
66
68
  <div v-if="!hasIssues" class="py-6 text-center text-sm text-slate-400">
67
69
  <UIcon name="i-lucide-check-circle-2" class="mx-auto mb-2 h-8 w-8 text-emerald-400" />
68
- All pipelines are valid and up to date.
70
+ {{ t('pipeline.health.allValid') }}
69
71
  </div>
70
72
 
71
73
  <div v-else class="space-y-5">
@@ -73,11 +75,12 @@ const reseedableCount = computed(
73
75
  <section v-if="invalid.length" class="space-y-2">
74
76
  <div class="flex items-center gap-2">
75
77
  <UIcon name="i-lucide-triangle-alert" class="h-4 w-4 text-rose-400" />
76
- <h3 class="text-sm font-semibold text-slate-200">Invalid pipelines</h3>
78
+ <h3 class="text-sm font-semibold text-slate-200">
79
+ {{ t('pipeline.health.invalidHeading') }}
80
+ </h3>
77
81
  </div>
78
82
  <p class="text-[11px] text-slate-500">
79
- These reference a missing agent or are misconfigured, so they would fail (or misrun) at
80
- start. Delete a custom pipeline, or reseed a built-in to restore its catalog definition.
83
+ {{ t('pipeline.health.invalidDescription') }}
81
84
  </p>
82
85
  <ul class="space-y-2">
83
86
  <li
@@ -92,7 +95,7 @@ const reseedableCount = computed(
92
95
  {{ h.pipeline.name }}
93
96
  </span>
94
97
  <UBadge v-if="h.pipeline.builtin" color="neutral" variant="subtle" size="xs">
95
- built-in
98
+ {{ t('pipeline.health.builtinBadge') }}
96
99
  </UBadge>
97
100
  </div>
98
101
  <ul class="mt-1 space-y-0.5">
@@ -116,7 +119,7 @@ const reseedableCount = computed(
116
119
  :disabled="anyBusy"
117
120
  @click="reseed(h.pipeline.id)"
118
121
  >
119
- Reseed
122
+ {{ t('pipeline.health.reseed') }}
120
123
  </UButton>
121
124
  <UButton
122
125
  v-else
@@ -128,7 +131,7 @@ const reseedableCount = computed(
128
131
  :disabled="anyBusy"
129
132
  @click="remove(h.pipeline.id)"
130
133
  >
131
- Delete
134
+ {{ t('pipeline.health.delete') }}
132
135
  </UButton>
133
136
  </div>
134
137
  </li>
@@ -139,11 +142,12 @@ const reseedableCount = computed(
139
142
  <section v-if="outdated.length" class="space-y-2">
140
143
  <div class="flex items-center gap-2">
141
144
  <UIcon name="i-lucide-arrow-up-circle" class="h-4 w-4 text-amber-400" />
142
- <h3 class="text-sm font-semibold text-slate-200">Updates available</h3>
145
+ <h3 class="text-sm font-semibold text-slate-200">
146
+ {{ t('pipeline.health.updatesHeading') }}
147
+ </h3>
143
148
  </div>
144
149
  <p class="text-[11px] text-slate-500">
145
- A newer version of these built-in pipelines has shipped. Reseed to adopt it (your labels
146
- and archive state are kept).
150
+ {{ t('pipeline.health.updatesDescription') }}
147
151
  </p>
148
152
  <ul class="space-y-2">
149
153
  <li
@@ -166,7 +170,7 @@ const reseedableCount = computed(
166
170
  :disabled="anyBusy"
167
171
  @click="reseed(h.pipeline.id)"
168
172
  >
169
- Reseed
173
+ {{ t('pipeline.health.reseed') }}
170
174
  </UButton>
171
175
  </li>
172
176
  </ul>
@@ -184,7 +188,7 @@ const reseedableCount = computed(
184
188
  :loading="anyBusy"
185
189
  @click="reseedAll"
186
190
  >
187
- Reseed all ({{ reseedableCount }})
191
+ {{ t('pipeline.health.reseedAll', { count: reseedableCount }) }}
188
192
  </UButton>
189
193
  <span v-else />
190
194
  <UButton
@@ -193,7 +197,7 @@ const reseedableCount = computed(
193
197
  :disabled="anyBusy"
194
198
  @click="ui.closePipelineHealth()"
195
199
  >
196
- {{ hasIssues ? 'Dismiss' : 'Done' }}
200
+ {{ hasIssues ? t('pipeline.health.dismiss') : t('pipeline.health.done') }}
197
201
  </UButton>
198
202
  </div>
199
203
  </template>
@@ -22,6 +22,7 @@ const models = useModelsStore()
22
22
  const ui = useUiStore()
23
23
  const execution = useExecutionStore()
24
24
  const reviews = useReviewStage()
25
+ const { t } = useI18n()
25
26
 
26
27
  // While an iterative reviewer gate (requirements-review / clarity-review) folds the
27
28
  // answers / re-reviews in the background it needs NO human, so its parked approval is
@@ -30,11 +31,11 @@ function reviewStageLabel(agentKind: string | undefined): string | null {
30
31
  if (!reviews.isBackground(agentKind, props.instance.blockId)) return null
31
32
  const stage = reviews.stageForBlock(props.instance.blockId)
32
33
  return stage === 'incorporating'
33
- ? 'Incorporating…'
34
+ ? t('pipeline.progress.stage.incorporating')
34
35
  : stage === 'reviewing'
35
- ? 'Re-reviewing'
36
+ ? t('pipeline.progress.stage.reviewing')
36
37
  : stage === 'recommending'
37
- ? 'Recommending…'
38
+ ? t('pipeline.progress.stage.recommending')
38
39
  : null
39
40
  }
40
41
 
@@ -51,9 +52,11 @@ function followUpPending(step: PipelineStep): number {
51
52
  }
52
53
  function followUpLabel(step: PipelineStep): string {
53
54
  const items = step.followUps?.items ?? []
54
- if (items.length === 0) return 'Watching…'
55
+ if (items.length === 0) return t('pipeline.progress.followUp.watching')
55
56
  const pending = followUpPending(step)
56
- return pending > 0 ? `${pending} to decide` : 'All decided'
57
+ return pending > 0
58
+ ? t('pipeline.progress.followUp.toDecide', { count: pending })
59
+ : t('pipeline.progress.followUp.allDecided')
57
60
  }
58
61
 
59
62
  // --- restart from a step -----------------------------------------------------
@@ -79,21 +82,41 @@ async function restartFromHere(i: number) {
79
82
  }
80
83
 
81
84
  /** Visual language for an individual agent's runtime state. */
82
- const STATE_META: Record<AgentState, { label: string; color: string; icon: string }> = {
83
- pending: { label: 'Pending', color: '#64748b', icon: 'i-lucide-circle-dashed' },
84
- working: { label: 'Working', color: '#6366f1', icon: 'i-lucide-loader' },
85
- waiting_decision: { label: 'Needs decision', color: '#f59e0b', icon: 'i-lucide-circle-help' },
86
- done: { label: 'Done', color: '#22c55e', icon: 'i-lucide-circle-check' },
87
- }
85
+ const STATE_META = computed<Record<AgentState, { label: string; color: string; icon: string }>>(
86
+ () => ({
87
+ pending: {
88
+ label: t('pipeline.progress.state.pending'),
89
+ color: '#64748b',
90
+ icon: 'i-lucide-circle-dashed',
91
+ },
92
+ working: {
93
+ label: t('pipeline.progress.state.working'),
94
+ color: '#6366f1',
95
+ icon: 'i-lucide-loader',
96
+ },
97
+ waiting_decision: {
98
+ label: t('pipeline.progress.state.waiting_decision'),
99
+ color: '#f59e0b',
100
+ icon: 'i-lucide-circle-help',
101
+ },
102
+ done: {
103
+ label: t('pipeline.progress.state.done'),
104
+ color: '#22c55e',
105
+ icon: 'i-lucide-circle-check',
106
+ },
107
+ }),
108
+ )
88
109
 
89
110
  /** Visual language for the pipeline instance as a whole. */
90
- const STATUS_META: Record<ExecutionInstance['status'], { label: string; chip: string }> = {
91
- running: { label: 'Running', chip: 'primary' },
92
- blocked: { label: 'Needs you', chip: 'warning' },
93
- paused: { label: 'Paused (budget)', chip: 'neutral' },
94
- done: { label: 'Completed', chip: 'success' },
95
- failed: { label: 'Failed', chip: 'error' },
96
- }
111
+ const STATUS_META = computed<Record<ExecutionInstance['status'], { label: string; chip: string }>>(
112
+ () => ({
113
+ running: { label: t('pipeline.progress.status.running'), chip: 'primary' },
114
+ blocked: { label: t('pipeline.progress.status.blocked'), chip: 'warning' },
115
+ paused: { label: t('pipeline.progress.status.paused'), chip: 'neutral' },
116
+ done: { label: t('pipeline.progress.status.done'), chip: 'success' },
117
+ failed: { label: t('pipeline.progress.status.failed'), chip: 'error' },
118
+ }),
119
+ )
97
120
 
98
121
  const steps = computed(() => props.instance.steps)
99
122
  const total = computed(() => steps.value.length)
@@ -116,7 +139,7 @@ function liveWorking(state: AgentState) {
116
139
  * failed reads as "Failed" with a red cross, not a frozen "Working" loader.
117
140
  */
118
141
  function stepVisual(state: AgentState) {
119
- return isFailedStep(state, runFailed.value) ? FAILED_STEP_META : STATE_META[state]
142
+ return isFailedStep(state, runFailed.value) ? FAILED_STEP_META : STATE_META.value[state]
120
143
  }
121
144
 
122
145
  /** A step counts as fully complete only once its state is `done`. */
@@ -135,7 +158,7 @@ const overallProgress = computed(() => {
135
158
  })
136
159
  const overallPct = computed(() => Math.round(overallProgress.value * 100))
137
160
 
138
- const statusMeta = computed(() => STATUS_META[props.instance.status])
161
+ const statusMeta = computed(() => STATUS_META.value[props.instance.status])
139
162
 
140
163
  /** The agent the pipeline is currently centred on (for the summary line). */
141
164
  const currentAgent = computed(() => {
@@ -171,13 +194,19 @@ const ITEM_ICON: Record<string, string> = {
171
194
  <div class="flex flex-wrap items-center gap-3">
172
195
  <UBadge :color="statusMeta.chip as any" variant="subtle">{{ statusMeta.label }}</UBadge>
173
196
  <span class="text-sm text-slate-300">
174
- <span class="font-semibold text-white">{{ completedCount }}</span>
175
- / {{ total }} agents complete
197
+ <i18n-t keypath="pipeline.progress.agentsComplete" tag="span" scope="global">
198
+ <template #completed>
199
+ <span class="font-semibold text-white">{{ completedCount }}</span>
200
+ </template>
201
+ <template #total>{{ total }}</template>
202
+ </i18n-t>
176
203
  </span>
177
204
  <span v-if="currentAgent && instance.status === 'running'" class="text-xs text-slate-500">
178
- · currently {{ currentAgent }}
205
+ · {{ t('pipeline.progress.currently', { agent: currentAgent }) }}
179
206
  </span>
180
- <span class="ml-auto font-mono text-sm tabular-nums text-slate-200">{{ overallPct }}%</span>
207
+ <span class="ml-auto font-mono text-sm tabular-nums text-slate-200">{{
208
+ t('pipeline.progress.percent', { value: overallPct })
209
+ }}</span>
181
210
  </div>
182
211
  <UProgress :model-value="overallPct" class="mt-3" />
183
212
 
@@ -233,7 +262,11 @@ const ITEM_ICON: Record<string, string> = {
233
262
  >
234
263
  <div
235
264
  class="group flex cursor-pointer items-center gap-2"
236
- :title="s.output ? 'View details & read output' : 'View step details'"
265
+ :title="
266
+ s.output
267
+ ? t('pipeline.progress.viewDetailsOutput')
268
+ : t('pipeline.progress.viewDetails')
269
+ "
237
270
  @click="openStep(i)"
238
271
  >
239
272
  <div
@@ -254,13 +287,13 @@ const ITEM_ICON: Record<string, string> = {
254
287
  <span
255
288
  v-if="isCompanionKind(s.agentKind)"
256
289
  class="shrink-0 rounded bg-slate-700/60 px-1 text-[9px] font-medium uppercase tracking-wide text-slate-300"
257
- title="Companion of a producer step"
290
+ :title="t('pipeline.progress.companionTooltip')"
258
291
  >
259
- Companion
292
+ {{ t('pipeline.progress.companion') }}
260
293
  </span>
261
294
  </div>
262
295
  <div class="text-[10px] uppercase tracking-wide text-slate-500">
263
- Step {{ i + 1 }} of {{ total }}
296
+ {{ t('pipeline.progress.stepOf', { current: i + 1, total }) }}
264
297
  </div>
265
298
  </div>
266
299
  <span
@@ -281,7 +314,7 @@ const ITEM_ICON: Record<string, string> = {
281
314
  variant="ghost"
282
315
  size="xs"
283
316
  class="shrink-0 opacity-0 transition-opacity group-hover:opacity-100"
284
- title="Restart pipeline from this step"
317
+ :title="t('pipeline.progress.restartTooltip')"
285
318
  @click.stop="restartArmed = i"
286
319
  />
287
320
  <template v-else>
@@ -294,7 +327,7 @@ const ITEM_ICON: Record<string, string> = {
294
327
  class="shrink-0"
295
328
  @click.stop="restartFromHere(i)"
296
329
  >
297
- Restart from here
330
+ {{ t('pipeline.progress.restartFromHere') }}
298
331
  </UButton>
299
332
  <UButton
300
333
  color="neutral"
@@ -304,7 +337,7 @@ const ITEM_ICON: Record<string, string> = {
304
337
  :disabled="restarting === i"
305
338
  @click.stop="restartArmed = null"
306
339
  >
307
- Cancel
340
+ {{ t('common.cancel') }}
308
341
  </UButton>
309
342
  </template>
310
343
  </template>
@@ -330,16 +363,21 @@ const ITEM_ICON: Record<string, string> = {
330
363
  class="mt-2 flex items-center gap-1.5 text-[11px] text-sky-300"
331
364
  >
332
365
  <UIcon name="i-lucide-loader-circle" class="h-3.5 w-3.5 shrink-0 animate-spin" />
333
- <span>Spinning up container…</span>
366
+ <span>{{ t('pipeline.progress.spinningUpContainer') }}</span>
334
367
  </div>
335
368
 
336
369
  <!-- live subtask counts from the agent's todo list -->
337
370
  <div v-if="s.subtasks && s.subtasks.total > 0" class="mt-2">
338
371
  <div class="flex items-center justify-between text-[10px] text-slate-400">
339
372
  <span>
340
- {{ s.subtasks.completed }}/{{ s.subtasks.total }} subtasks
373
+ {{
374
+ t('pipeline.progress.subtasks', {
375
+ completed: s.subtasks.completed,
376
+ total: s.subtasks.total,
377
+ })
378
+ }}
341
379
  <span v-if="s.subtasks.inProgress > 0" class="text-indigo-300">
342
- · {{ s.subtasks.inProgress }} in progress
380
+ {{ t('pipeline.progress.subtasksInProgress', { count: s.subtasks.inProgress }) }}
343
381
  </span>
344
382
  </span>
345
383
  </div>
@@ -399,7 +437,7 @@ const ITEM_ICON: Record<string, string> = {
399
437
  all step metadata) lives in the step-detail overlay opened by click. -->
400
438
  <p v-if="s.output" class="mt-2 flex items-center gap-1 text-[11px] text-slate-500">
401
439
  <UIcon name="i-lucide-book-open-text" class="h-3 w-3 shrink-0" />
402
- Click to read this agent’s output
440
+ {{ t('pipeline.progress.clickToRead') }}
403
441
  </p>
404
442
 
405
443
  <!-- Conditionally-run companion (today the Tester's fixer): a distinct
@@ -423,7 +461,7 @@ const ITEM_ICON: Record<string, string> = {
423
461
  </span>
424
462
  <span class="min-w-0 flex-1 truncate text-[12px] text-slate-300">
425
463
  {{ agentKindMeta(companionByStep[i]!.kind).label }}
426
- <span class="text-slate-500">(companion)</span>
464
+ <span class="text-slate-500">{{ t('pipeline.progress.companionSuffix') }}</span>
427
465
  </span>
428
466
  <span
429
467
  class="shrink-0 text-[11px] font-medium"
@@ -454,7 +492,7 @@ const ITEM_ICON: Record<string, string> = {
454
492
  </span>
455
493
  <span class="min-w-0 flex-1 truncate text-[12px] text-slate-300">
456
494
  {{ FOLLOW_UP_COMPANION_META.label }}
457
- <span class="text-slate-500">(companion)</span>
495
+ <span class="text-slate-500">{{ t('pipeline.progress.companionSuffix') }}</span>
458
496
  </span>
459
497
  <span
460
498
  class="shrink-0 text-[11px] font-medium"
@@ -483,7 +521,9 @@ const ITEM_ICON: Record<string, string> = {
483
521
  icon="i-lucide-shield-check"
484
522
  @click="emit('openApproval', s.approval.id)"
485
523
  >
486
- Review &amp; approve {{ agentKindMeta(s.agentKind).label }}'s proposal
524
+ {{
525
+ t('pipeline.progress.reviewApprove', { agent: agentKindMeta(s.agentKind).label })
526
+ }}
487
527
  </UButton>
488
528
  </div>
489
529
 
@@ -496,7 +536,7 @@ const ITEM_ICON: Record<string, string> = {
496
536
  icon="i-lucide-circle-help"
497
537
  @click="emit('openDecision', s.decision.id)"
498
538
  >
499
- Resolve: {{ s.decision.question }}
539
+ {{ t('pipeline.progress.resolve', { question: s.decision.question }) }}
500
540
  </UButton>
501
541
  </div>
502
542
  <p
@@ -9,6 +9,7 @@
9
9
  // agent step and the spec-writer consume.
10
10
  import { parseOutputOutline } from '~/utils/agentOutput'
11
11
  import StepRestartControl from '~/components/panels/StepRestartControl.vue'
12
+ import IterationCapPrompt from '~/components/pipeline/IterationCapPrompt.vue'
12
13
  import type {
13
14
  RequirementRecommendation,
14
15
  RequirementReview,
@@ -3,6 +3,7 @@ import BoardCanvas from '~/components/board/BoardCanvas.vue'
3
3
  import SideBar from '~/components/layout/SideBar.vue'
4
4
  import BoardToolbar from '~/components/layout/BoardToolbar.vue'
5
5
  import SpendWarningBanner from '~/components/layout/SpendWarningBanner.vue'
6
+ import TranslationWarningBanner from '~/components/layout/TranslationWarningBanner.vue'
6
7
  import GitHubPatBanner from '~/components/layout/GitHubPatBanner.vue'
7
8
  import AiProvidersBanner from '~/components/layout/AiProvidersBanner.vue'
8
9
  import ProviderConfigBanner from '~/components/layout/ProviderConfigBanner.vue'
@@ -2166,5 +2166,217 @@
2166
2166
  "updateConnection": "Update connection",
2167
2167
  "connect": "Connect"
2168
2168
  }
2169
+ },
2170
+ "pipeline": {
2171
+ "iterationCap": {
2172
+ "extraRound": "One more round",
2173
+ "proceed": "Proceed anyway",
2174
+ "stopReset": "Stop & reset task"
2175
+ },
2176
+ "builder": {
2177
+ "title": "Pipeline builder",
2178
+ "agentPalette": "Agent palette",
2179
+ "addAgent": "Add agent",
2180
+ "pipeline": "Pipeline",
2181
+ "configureModels": "Configure models",
2182
+ "configureModelsTooltip": "Manage model presets (which model each agent runs on)",
2183
+ "namePlaceholder": "Pipeline name",
2184
+ "labelPlaceholder": "+ label",
2185
+ "gatingNeedsEstimator": "A gated step needs a Task Estimator before it. Add one or the pipeline won't save.",
2186
+ "emptyDraft": "Click agents on the left to assemble a linear pipeline.",
2187
+ "companionAdd": "Add the {companion} (reviews this step, loops it back below threshold)",
2188
+ "companionRemove": "Remove the {companion} for this step",
2189
+ "disableTooltip": "Disable this step (kept in the pipeline but skipped at run)",
2190
+ "enableTooltip": "Step disabled (skipped at run). Click to enable.",
2191
+ "approvalAddTooltip": "Require human approval after this step",
2192
+ "approvalRemoveTooltip": "Approval required after this step. Click to remove the gate.",
2193
+ "consensusEnableTooltip": "Enable consensus (multi-model panel/debate/voting) for this step",
2194
+ "consensusRevertTooltip": "Consensus enabled. Click to revert to a single agent.",
2195
+ "followUpEnableTooltip": "Follow-up companion disabled. Click to enable (Coder surfaces loose ends / questions).",
2196
+ "followUpDisableTooltip": "Follow-up companion enabled. Coder surfaces loose ends / side-tasks / questions; click to disable.",
2197
+ "moveUp": "Move step up",
2198
+ "moveDown": "Move step down",
2199
+ "removeStep": "Remove this step from the pipeline",
2200
+ "gateOnEstimate": "Gate on estimate",
2201
+ "companionGateTooltip": "Only run this companion when the task estimate clears a threshold (needs a Task Estimator earlier)",
2202
+ "consensusGateTooltip": "Only run consensus when the task estimate clears a threshold (else the standard agent runs)",
2203
+ "runWhenAny": "run when (any):",
2204
+ "complexityThreshold": "complexity ≥",
2205
+ "riskThreshold": "risk ≥",
2206
+ "impactThreshold": "impact ≥",
2207
+ "strategy": "Strategy",
2208
+ "rounds": "Rounds",
2209
+ "strategyOption": {
2210
+ "specialist-panel": "Specialist panel",
2211
+ "debate": "Debate",
2212
+ "ranked-voting": "Ranked voting"
2213
+ },
2214
+ "rolePlaceholder": "Role",
2215
+ "modelIdPlaceholder": "Model id (optional)",
2216
+ "removeParticipant": "Remove participant (min 2)",
2217
+ "addParticipant": "Add participant",
2218
+ "savedPipelines": "Saved pipelines",
2219
+ "hideArchived": "Hide archived",
2220
+ "archivedCount": "Archived ({count})",
2221
+ "allLabels": "All",
2222
+ "defaultBadge": "default",
2223
+ "stepCount": "{count} step | {count} steps",
2224
+ "unarchive": "Unarchive",
2225
+ "archive": "Archive (hide from the default view)",
2226
+ "cloneDefault": "Clone this default into an editable copy",
2227
+ "clone": "Clone",
2228
+ "edit": "Edit this pipeline",
2229
+ "delete": "Delete this pipeline",
2230
+ "disabledStepTooltip": "Disabled, skipped at run",
2231
+ "cancelEdit": "Cancel edit",
2232
+ "clear": "Clear",
2233
+ "update": "Update pipeline",
2234
+ "save": "Save pipeline",
2235
+ "addAgentModal": {
2236
+ "title": "Add agent",
2237
+ "name": "Name",
2238
+ "namePlaceholder": "e.g. Security Auditor",
2239
+ "description": "Description",
2240
+ "descriptionPlaceholder": "What does this agent do?",
2241
+ "linkDoc": "Link context document",
2242
+ "create": "Create agent"
2243
+ },
2244
+ "toast": {
2245
+ "added": "Added agent \"{name}\"",
2246
+ "placeholderTitle": "Placeholder",
2247
+ "updated": "Updated \"{name}\"",
2248
+ "saved": "Saved \"{name}\"",
2249
+ "addOneFirst": "Add at least one agent first",
2250
+ "saveFailed": "Could not save pipeline",
2251
+ "cloned": "Cloned \"{name}\" — now editing \"{copy}\"",
2252
+ "cloneFailed": "Could not clone pipeline",
2253
+ "updateFailed": "Could not update pipeline"
2254
+ }
2255
+ },
2256
+ "progress": {
2257
+ "status": {
2258
+ "running": "Running",
2259
+ "blocked": "Needs you",
2260
+ "paused": "Paused (budget)",
2261
+ "done": "Completed",
2262
+ "failed": "Failed"
2263
+ },
2264
+ "state": {
2265
+ "pending": "Pending",
2266
+ "working": "Working",
2267
+ "waiting_decision": "Needs decision",
2268
+ "done": "Done"
2269
+ },
2270
+ "stage": {
2271
+ "incorporating": "Incorporating…",
2272
+ "reviewing": "Re-reviewing…",
2273
+ "recommending": "Recommending…"
2274
+ },
2275
+ "followUp": {
2276
+ "watching": "Watching…",
2277
+ "toDecide": "{count} to decide",
2278
+ "allDecided": "All decided"
2279
+ },
2280
+ "agentsComplete": "{completed} / {total} agents complete",
2281
+ "currently": "currently {agent}",
2282
+ "percent": "{value}%",
2283
+ "companion": "Companion",
2284
+ "companionTooltip": "Companion of a producer step",
2285
+ "companionSuffix": "(companion)",
2286
+ "stepOf": "Step {current} of {total}",
2287
+ "viewDetailsOutput": "View details and read output",
2288
+ "viewDetails": "View step details",
2289
+ "restartTooltip": "Restart pipeline from this step",
2290
+ "restartFromHere": "Restart from here",
2291
+ "spinningUpContainer": "Spinning up container…",
2292
+ "subtasks": "{completed}/{total} subtasks",
2293
+ "subtasksInProgress": "· {count} in progress",
2294
+ "clickToRead": "Click to read this agent's output",
2295
+ "reviewApprove": "Review & approve {agent}'s proposal",
2296
+ "resolve": "Resolve: {question}"
2297
+ },
2298
+ "health": {
2299
+ "title": "Pipeline health",
2300
+ "allValid": "All pipelines are valid and up to date.",
2301
+ "invalidHeading": "Invalid pipelines",
2302
+ "invalidDescription": "These reference a missing agent or are misconfigured, so they would fail (or misrun) at start. Delete a custom pipeline, or reseed a built-in to restore its catalog definition.",
2303
+ "builtinBadge": "built-in",
2304
+ "reseed": "Reseed",
2305
+ "delete": "Delete",
2306
+ "updatesHeading": "Updates available",
2307
+ "updatesDescription": "A newer version of these built-in pipelines has shipped. Reseed to adopt it (your labels and archive state are kept).",
2308
+ "reseedAll": "Reseed all ({count})",
2309
+ "dismiss": "Dismiss",
2310
+ "done": "Done",
2311
+ "toast": {
2312
+ "reseedFailed": "Could not reseed pipeline",
2313
+ "deleteFailed": "Could not delete pipeline"
2314
+ }
2315
+ }
2316
+ },
2317
+ "palette": {
2318
+ "hint": "Click an agent to append it to the pipeline.",
2319
+ "customAgents": "Custom agents"
2320
+ },
2321
+ "gates": {
2322
+ "subtitle": {
2323
+ "humanReview": "Waits for a human code review on the PR, looping the fixer on comments",
2324
+ "ci": "Gates the PR on green CI, looping the CI fixer on failure",
2325
+ "conflicts": "Gates the PR on a clean merge, looping the resolver on conflicts"
2326
+ },
2327
+ "status": {
2328
+ "passed": "Passed",
2329
+ "gaveUp": "Gave up",
2330
+ "fixing": "Fixing",
2331
+ "failing": "Failing",
2332
+ "pending": "Pending",
2333
+ "checking": "Checking"
2334
+ },
2335
+ "conflict": {
2336
+ "mergeable": "Mergeable",
2337
+ "computing": "Computing mergeability…",
2338
+ "conflicts": "Conflicts with base",
2339
+ "unknown": "Unknown"
2340
+ },
2341
+ "noActivity": "No gate activity yet.",
2342
+ "noActivityHint": "The precheck runs once the PR is open. While it polls, the step shows live state on the board.",
2343
+ "passedCi": "CI is green.",
2344
+ "passedConflicts": "The PR merges cleanly with its base.",
2345
+ "humanReview": {
2346
+ "approvals": "{approved} / {required} approval | {approved} / {required} approvals",
2347
+ "suffixFixing": "· fixer addressing comments…",
2348
+ "suffixFailing": "· review comments to address",
2349
+ "suffixAwaiting": "· awaiting review",
2350
+ "reviewPr": "Review pull request on GitHub",
2351
+ "requestFixHeading": "Request a fix",
2352
+ "requestFixDescription": "Describe a change for the fixer to make on the PR branch now (in addition to any review comments, which it addresses automatically).",
2353
+ "requestFixPlaceholder": "e.g. rename the helper and add a unit test for the empty-input case",
2354
+ "requestFix": "Request fix"
2355
+ },
2356
+ "ci": {
2357
+ "failingChecks": "Failing checks",
2358
+ "openOnGithub": "Open {name} on GitHub",
2359
+ "conclusionFallback": "failure",
2360
+ "failureFallback": "CI has not reported a failure on this commit."
2361
+ },
2362
+ "conflicts": {
2363
+ "mergeability": "Mergeability",
2364
+ "viewPr": "View pull request on GitHub"
2365
+ },
2366
+ "attemptsHeading": "{helper} attempts",
2367
+ "attempt": "Attempt {number}",
2368
+ "outcome": {
2369
+ "completed": "completed",
2370
+ "failed": "failed"
2371
+ },
2372
+ "sidebar": {
2373
+ "state": "State",
2374
+ "fixRounds": "{count} fix round | {count} fix rounds",
2375
+ "attempts": "{attempts}/{max} attempt | {attempts}/{max} attempts",
2376
+ "suffixRunning": "· running…",
2377
+ "suffixNotNeeded": "· not needed yet",
2378
+ "gatedCommit": "Gated commit",
2379
+ "footer": "A gate runs a programmatic precheck and only spins up the {helper} when it fails; a green check advances with nothing spun up."
2380
+ }
2169
2381
  }
2170
2382
  }