@cat-factory/app 0.150.1 → 0.151.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.
- package/app/components/board/AddTaskModal.vue +43 -2
- package/app/components/board/ReviewDebtBadge.vue +26 -0
- package/app/components/board/ReviewFrictionDialog.vue +118 -0
- package/app/components/panels/inspector/ContainerSummary.vue +7 -3
- package/app/components/settings/WorkspaceSettingsPanel.vue +118 -1
- package/app/composables/api/board.ts +1 -0
- package/app/composables/usePipelineErrorToast.ts +12 -0
- package/app/composables/useReviewDebt.ts +23 -0
- package/app/pages/index.vue +2 -0
- package/app/stores/board/mutations.ts +4 -0
- package/app/stores/ui/modals.ts +40 -0
- package/app/stores/workspaceSettings.ts +4 -0
- package/app/types/domain.ts +1 -0
- package/i18n/locales/de.json +33 -0
- package/i18n/locales/en.json +33 -0
- package/i18n/locales/es.json +33 -0
- package/i18n/locales/fr.json +33 -0
- package/i18n/locales/he.json +33 -0
- package/i18n/locales/it.json +33 -0
- package/i18n/locales/ja.json +33 -0
- package/i18n/locales/pl.json +33 -0
- package/i18n/locales/tr.json +33 -0
- package/i18n/locales/uk.json +33 -0
- package/package.json +2 -2
|
@@ -28,6 +28,7 @@ import ContextDocumentPicker from '~/components/documents/ContextDocumentPicker.
|
|
|
28
28
|
import ContextIssuePicker from '~/components/tasks/ContextIssuePicker.vue'
|
|
29
29
|
import FragmentSelector from '~/components/fragments/FragmentSelector.vue'
|
|
30
30
|
import { riskPolicyOptionLabel, riskPolicySummary } from '~/utils/riskPolicy'
|
|
31
|
+
import { parseConflict } from '~/composables/usePipelineErrorToast'
|
|
31
32
|
import { pipelineAllowedForManualStart } from '~/utils/pipeline'
|
|
32
33
|
|
|
33
34
|
const ui = useUiStore()
|
|
@@ -678,8 +679,7 @@ const canAdd = computed(() => {
|
|
|
678
679
|
})
|
|
679
680
|
|
|
680
681
|
async function add() {
|
|
681
|
-
|
|
682
|
-
if (!containerId || !canAdd.value) return
|
|
682
|
+
if (!canAdd.value) return
|
|
683
683
|
// Recurring tasks are created via a schedule on the service frame — hand off to the
|
|
684
684
|
// existing recurring-pipeline modal (which carries the cadence + prompt).
|
|
685
685
|
if (isRecurring.value) {
|
|
@@ -689,6 +689,17 @@ async function add() {
|
|
|
689
689
|
ui.openAddRecurring(frameId)
|
|
690
690
|
return
|
|
691
691
|
}
|
|
692
|
+
await submitCreate(false)
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
/**
|
|
696
|
+
* Create the task, optionally acknowledging review-debt friction. A `review_debt_*` 409 opens the
|
|
697
|
+
* friction dialog instead of a bare error toast: the soft `warn` tier's dialog can retry via
|
|
698
|
+
* `submitCreate(true)` (the `onConfirm`), while a hard `blocked` tier only offers "Go review".
|
|
699
|
+
*/
|
|
700
|
+
async function submitCreate(acknowledgeReviewDebt: boolean) {
|
|
701
|
+
const containerId = ui.addTaskContainerId
|
|
702
|
+
if (!containerId) return
|
|
692
703
|
saving.value = true
|
|
693
704
|
try {
|
|
694
705
|
const typeFields = buildTypeFields()
|
|
@@ -718,6 +729,7 @@ async function add() {
|
|
|
718
729
|
// re-seeded from the service. The task owns its fragments from here.
|
|
719
730
|
fragmentIds: [...fragmentIds.value],
|
|
720
731
|
...(technical.value ? { technical: true } : {}),
|
|
732
|
+
...(acknowledgeReviewDebt ? { acknowledgeReviewDebt: true } : {}),
|
|
721
733
|
})
|
|
722
734
|
if (block) {
|
|
723
735
|
// Surface the SPECIFIC cause of any attachment that couldn't be linked (a GitHub
|
|
@@ -725,8 +737,14 @@ async function add() {
|
|
|
725
737
|
// one-click "Copy details" for a bug report.
|
|
726
738
|
presentLinkFailures(await linkPending(block.id, pendingContext.value), block.id)
|
|
727
739
|
}
|
|
740
|
+
ui.closeReviewFriction()
|
|
728
741
|
ui.closeAddTask()
|
|
729
742
|
} catch (e) {
|
|
743
|
+
const conflict = parseConflict(e)
|
|
744
|
+
if (conflict?.reason === 'review_debt_warn' || conflict?.reason === 'review_debt_blocked') {
|
|
745
|
+
openReviewFrictionDialog(conflict)
|
|
746
|
+
return
|
|
747
|
+
}
|
|
730
748
|
toast.add({
|
|
731
749
|
title: t('board.addTask.addFailedTitle'),
|
|
732
750
|
description: e instanceof Error ? e.message : String(e),
|
|
@@ -737,6 +755,29 @@ async function add() {
|
|
|
737
755
|
saving.value = false
|
|
738
756
|
}
|
|
739
757
|
}
|
|
758
|
+
|
|
759
|
+
/** Turn a parsed review-debt friction 409 into the dialog context (see ReviewFrictionDialog.vue). */
|
|
760
|
+
function openReviewFrictionDialog(conflict: NonNullable<ReturnType<typeof parseConflict>>) {
|
|
761
|
+
const details = conflict.details
|
|
762
|
+
const rawDebt = Array.isArray(details.debt) ? details.debt : []
|
|
763
|
+
const debt = rawDebt.map((d) => {
|
|
764
|
+
const row = (d ?? {}) as { blockId?: unknown; title?: unknown; waitingMinutes?: unknown }
|
|
765
|
+
return {
|
|
766
|
+
blockId: typeof row.blockId === 'string' ? row.blockId : '',
|
|
767
|
+
title: typeof row.title === 'string' ? row.title : null,
|
|
768
|
+
waitingMinutes: typeof row.waitingMinutes === 'number' ? row.waitingMinutes : 0,
|
|
769
|
+
}
|
|
770
|
+
})
|
|
771
|
+
const isWarn = conflict.reason === 'review_debt_warn'
|
|
772
|
+
ui.openReviewFriction({
|
|
773
|
+
kind: isWarn ? 'warn' : 'blocked',
|
|
774
|
+
reason:
|
|
775
|
+
details.friction === 'count' || details.friction === 'stuck' ? details.friction : undefined,
|
|
776
|
+
threshold: typeof details.threshold === 'number' ? details.threshold : null,
|
|
777
|
+
debt,
|
|
778
|
+
onConfirm: isWarn ? () => void submitCreate(true) : null,
|
|
779
|
+
})
|
|
780
|
+
}
|
|
740
781
|
</script>
|
|
741
782
|
|
|
742
783
|
<template>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
// A small pre-warn badge shown next to an "Add task" affordance when the workspace's opt-in
|
|
3
|
+
// review-debt friction is at (or past) its threshold, so the friction dialog isn't a surprise.
|
|
4
|
+
// Hidden entirely when friction is off or the queue is under the warn threshold. The server
|
|
5
|
+
// remains the authority — this is a hint. See backend/docs/review-debt-friction.md.
|
|
6
|
+
import { computed } from 'vue'
|
|
7
|
+
import { useReviewDebt } from '~/composables/useReviewDebt'
|
|
8
|
+
|
|
9
|
+
const { active, debtCount, blocked } = useReviewDebt()
|
|
10
|
+
const { t } = useI18n()
|
|
11
|
+
|
|
12
|
+
const color = computed(() => (blocked.value ? 'error' : 'warning'))
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<template>
|
|
16
|
+
<UBadge
|
|
17
|
+
v-if="active"
|
|
18
|
+
:color="color"
|
|
19
|
+
variant="subtle"
|
|
20
|
+
size="sm"
|
|
21
|
+
icon="i-lucide-clock"
|
|
22
|
+
:title="t('errors.reviewFriction.badge', { count: debtCount })"
|
|
23
|
+
>
|
|
24
|
+
{{ debtCount }}
|
|
25
|
+
</UBadge>
|
|
26
|
+
</template>
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
// Opt-in review-debt friction dialog. Shown when a task-create request is refused by the friction
|
|
3
|
+
// gate (a `review_debt_warn` / `review_debt_blocked` 409). It lists exactly which tasks are waiting
|
|
4
|
+
// on human review (worst first), each deep-linking to its block so "go review instead" is one
|
|
5
|
+
// click. The soft `warn` tier offers a secondary "Create anyway" (retries with the acknowledge
|
|
6
|
+
// flag); the hard `blocked` tier does not. Driven by `ui.reviewFrictionContext`, mounted in
|
|
7
|
+
// pages/index.vue. See backend/docs/review-debt-friction.md.
|
|
8
|
+
import { computed } from 'vue'
|
|
9
|
+
|
|
10
|
+
const { t } = useI18n()
|
|
11
|
+
const ui = useUiStore()
|
|
12
|
+
|
|
13
|
+
const ctx = computed(() => ui.reviewFrictionContext)
|
|
14
|
+
|
|
15
|
+
const open = computed({
|
|
16
|
+
get: () => ctx.value !== null,
|
|
17
|
+
set: (v: boolean) => {
|
|
18
|
+
if (!v) ui.closeReviewFriction()
|
|
19
|
+
},
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
const title = computed(() =>
|
|
23
|
+
ctx.value?.kind === 'blocked'
|
|
24
|
+
? t('errors.reviewFriction.blockedTitle')
|
|
25
|
+
: t('errors.reviewFriction.warnTitle'),
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
const body = computed(() => {
|
|
29
|
+
const c = ctx.value
|
|
30
|
+
if (!c) return ''
|
|
31
|
+
if (c.kind === 'warn') return t('errors.reviewFriction.warnBody', { count: c.debt.length })
|
|
32
|
+
if (c.reason === 'stuck')
|
|
33
|
+
return t('errors.reviewFriction.blockedStuckBody', { minutes: c.threshold ?? 0 })
|
|
34
|
+
return t('errors.reviewFriction.blockedCountBody', {
|
|
35
|
+
count: c.debt.length,
|
|
36
|
+
threshold: c.threshold ?? 0,
|
|
37
|
+
})
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
/** Deep-link to a waiting task's block and dismiss the whole friction flow. */
|
|
41
|
+
function goToBlock(blockId: string) {
|
|
42
|
+
if (blockId) ui.select(blockId)
|
|
43
|
+
ui.closeReviewFriction()
|
|
44
|
+
ui.closeAddTask()
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function goReview() {
|
|
48
|
+
const first = ctx.value?.debt[0]
|
|
49
|
+
if (first) goToBlock(first.blockId)
|
|
50
|
+
else {
|
|
51
|
+
ui.closeReviewFriction()
|
|
52
|
+
ui.closeAddTask()
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function createAnyway() {
|
|
57
|
+
ctx.value?.onConfirm?.()
|
|
58
|
+
}
|
|
59
|
+
</script>
|
|
60
|
+
|
|
61
|
+
<template>
|
|
62
|
+
<UModal v-model:open="open" :title="title" :ui="{ content: 'max-w-xl' }">
|
|
63
|
+
<template #body>
|
|
64
|
+
<div v-if="ctx" class="space-y-5">
|
|
65
|
+
<p class="text-sm text-slate-300">{{ body }}</p>
|
|
66
|
+
|
|
67
|
+
<div class="rounded-lg border border-slate-700 bg-slate-900/50 p-2">
|
|
68
|
+
<p class="mb-1.5 px-1 text-[11px] font-semibold uppercase tracking-wide text-slate-500">
|
|
69
|
+
{{ t('errors.reviewFriction.waitingHeading') }}
|
|
70
|
+
</p>
|
|
71
|
+
<ul class="space-y-1">
|
|
72
|
+
<li v-for="item in ctx.debt" :key="item.blockId">
|
|
73
|
+
<button
|
|
74
|
+
type="button"
|
|
75
|
+
class="flex w-full items-center justify-between gap-3 rounded-md px-2 py-1.5 text-left text-sm hover:bg-slate-800/60"
|
|
76
|
+
@click="goToBlock(item.blockId)"
|
|
77
|
+
>
|
|
78
|
+
<span class="truncate text-slate-200">
|
|
79
|
+
{{ item.title || t('errors.reviewFriction.untitled') }}
|
|
80
|
+
</span>
|
|
81
|
+
<span class="shrink-0 text-[12px] text-slate-500">
|
|
82
|
+
{{ t('errors.reviewFriction.waiting', { minutes: item.waitingMinutes }) }}
|
|
83
|
+
</span>
|
|
84
|
+
</button>
|
|
85
|
+
</li>
|
|
86
|
+
</ul>
|
|
87
|
+
</div>
|
|
88
|
+
|
|
89
|
+
<div class="flex flex-wrap justify-end gap-2">
|
|
90
|
+
<UButton
|
|
91
|
+
color="neutral"
|
|
92
|
+
variant="ghost"
|
|
93
|
+
size="sm"
|
|
94
|
+
@click="
|
|
95
|
+
() => {
|
|
96
|
+
open = false
|
|
97
|
+
}
|
|
98
|
+
"
|
|
99
|
+
>
|
|
100
|
+
{{ t('errors.reviewFriction.close') }}
|
|
101
|
+
</UButton>
|
|
102
|
+
<UButton
|
|
103
|
+
v-if="ctx.onConfirm"
|
|
104
|
+
color="neutral"
|
|
105
|
+
variant="subtle"
|
|
106
|
+
size="sm"
|
|
107
|
+
@click="createAnyway"
|
|
108
|
+
>
|
|
109
|
+
{{ t('errors.reviewFriction.createAnyway') }}
|
|
110
|
+
</UButton>
|
|
111
|
+
<UButton color="primary" size="sm" icon="i-lucide-list-checks" @click="goReview">
|
|
112
|
+
{{ t('errors.reviewFriction.goReview') }}
|
|
113
|
+
</UButton>
|
|
114
|
+
</div>
|
|
115
|
+
</div>
|
|
116
|
+
</template>
|
|
117
|
+
</UModal>
|
|
118
|
+
</template>
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import type { Block } from '~/types/domain'
|
|
3
3
|
import { STATUS_META } from '~/utils/catalog'
|
|
4
4
|
import InspectorSection from '~/components/panels/inspector/InspectorSection.vue'
|
|
5
|
+
import ReviewDebtBadge from '~/components/board/ReviewDebtBadge.vue'
|
|
5
6
|
|
|
6
7
|
const props = defineProps<{ block: Block }>()
|
|
7
8
|
|
|
@@ -61,9 +62,12 @@ function addTask() {
|
|
|
61
62
|
: t('inspector.container.tasks', { count: tasks.length })
|
|
62
63
|
}}
|
|
63
64
|
</span>
|
|
64
|
-
<
|
|
65
|
-
|
|
66
|
-
|
|
65
|
+
<div class="flex items-center gap-1.5">
|
|
66
|
+
<ReviewDebtBadge />
|
|
67
|
+
<UButton size="xs" variant="soft" color="primary" icon="i-lucide-plus" @click="addTask">
|
|
68
|
+
{{ t('inspector.container.addTask') }}
|
|
69
|
+
</UButton>
|
|
70
|
+
</div>
|
|
67
71
|
</div>
|
|
68
72
|
<ul v-if="tasks.length" class="space-y-1">
|
|
69
73
|
<li
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
// The latter three are body-only section components rendered in tabs here (no longer
|
|
9
9
|
// standalone modals).
|
|
10
10
|
import { reactive, ref, watch } from 'vue'
|
|
11
|
-
import type { TaskLimitMode } from '~/types/domain'
|
|
11
|
+
import type { ReviewFrictionMode, TaskLimitMode } from '~/types/domain'
|
|
12
12
|
import RiskPolicyPanel from '~/components/settings/RiskPolicyPanel.vue'
|
|
13
13
|
import IssueTrackerPanel from '~/components/settings/IssueTrackerPanel.vue'
|
|
14
14
|
import ServiceFragmentDefaultsPanel from '~/components/settings/ServiceFragmentDefaultsPanel.vue'
|
|
@@ -129,6 +129,12 @@ const MODES = computed<{ value: TaskLimitMode; label: string }[]>(() => [
|
|
|
129
129
|
{ value: 'per_type', label: t('settings.workspaceSettings.taskLimit.modes.per_type') },
|
|
130
130
|
])
|
|
131
131
|
|
|
132
|
+
const REVIEW_FRICTION_MODES = computed<{ value: ReviewFrictionMode; label: string }[]>(() => [
|
|
133
|
+
{ value: 'off', label: t('settings.workspaceSettings.reviewFriction.modes.off') },
|
|
134
|
+
{ value: 'warn', label: t('settings.workspaceSettings.reviewFriction.modes.warn') },
|
|
135
|
+
{ value: 'enforce', label: t('settings.workspaceSettings.reviewFriction.modes.enforce') },
|
|
136
|
+
])
|
|
137
|
+
|
|
132
138
|
/** The localized "Max {type} tasks" label for a per-type running-task limit input. */
|
|
133
139
|
function maxTaskTypeLabel(type: LimitTaskType): string {
|
|
134
140
|
const key = TASK_TYPE_KEYS[type]
|
|
@@ -145,6 +151,12 @@ const draft = reactive({
|
|
|
145
151
|
storeAgentContext: true,
|
|
146
152
|
artifactRetentionDays: 14,
|
|
147
153
|
kaizenEnabled: true,
|
|
154
|
+
reviewFrictionMode: 'off' as ReviewFrictionMode,
|
|
155
|
+
reviewFrictionWarnCount: 3,
|
|
156
|
+
reviewFrictionBlockCountEnabled: false,
|
|
157
|
+
reviewFrictionBlockCount: 10 as number,
|
|
158
|
+
reviewFrictionBlockStuckEnabled: false,
|
|
159
|
+
reviewFrictionBlockStuckMinutes: 1440 as number,
|
|
148
160
|
})
|
|
149
161
|
|
|
150
162
|
function hydrate() {
|
|
@@ -157,6 +169,14 @@ function hydrate() {
|
|
|
157
169
|
draft.storeAgentContext = s.storeAgentContext
|
|
158
170
|
draft.artifactRetentionDays = s.artifactRetentionDays
|
|
159
171
|
draft.kaizenEnabled = s.kaizenEnabled
|
|
172
|
+
draft.reviewFrictionMode = s.reviewFrictionMode
|
|
173
|
+
draft.reviewFrictionWarnCount = s.reviewFrictionWarnCount
|
|
174
|
+
// The hard-block knobs are nullable (null ⇒ that trigger is off); a per-trigger checkbox is
|
|
175
|
+
// enabled from whether a value is stored, defaulting the input to a sensible starting number.
|
|
176
|
+
draft.reviewFrictionBlockCountEnabled = s.reviewFrictionBlockCount != null
|
|
177
|
+
draft.reviewFrictionBlockCount = s.reviewFrictionBlockCount ?? 10
|
|
178
|
+
draft.reviewFrictionBlockStuckEnabled = s.reviewFrictionBlockStuckMinutes != null
|
|
179
|
+
draft.reviewFrictionBlockStuckMinutes = s.reviewFrictionBlockStuckMinutes ?? 1440
|
|
160
180
|
}
|
|
161
181
|
|
|
162
182
|
// `store.settings` is always replaced wholesale (store hydrate/update reassign the ref),
|
|
@@ -166,6 +186,25 @@ watch(() => store.settings, hydrate, { immediate: true })
|
|
|
166
186
|
const saving = ref(false)
|
|
167
187
|
|
|
168
188
|
async function save() {
|
|
189
|
+
// The hard-block triggers only apply in `enforce` mode; a disabled trigger sends null.
|
|
190
|
+
const blockCount =
|
|
191
|
+
draft.reviewFrictionMode === 'enforce' && draft.reviewFrictionBlockCountEnabled
|
|
192
|
+
? draft.reviewFrictionBlockCount
|
|
193
|
+
: null
|
|
194
|
+
const blockStuckMinutes =
|
|
195
|
+
draft.reviewFrictionMode === 'enforce' && draft.reviewFrictionBlockStuckEnabled
|
|
196
|
+
? draft.reviewFrictionBlockStuckMinutes
|
|
197
|
+
: null
|
|
198
|
+
// Mirror the backend's enforce-mode validation client-side so the user gets an immediate,
|
|
199
|
+
// localized message instead of the raw 422 (enforce needs at least one hard trigger).
|
|
200
|
+
if (draft.reviewFrictionMode === 'enforce' && blockCount == null && blockStuckMinutes == null) {
|
|
201
|
+
toast.add({
|
|
202
|
+
title: t('settings.workspaceSettings.reviewFriction.needsTrigger'),
|
|
203
|
+
icon: 'i-lucide-triangle-alert',
|
|
204
|
+
color: 'warning',
|
|
205
|
+
})
|
|
206
|
+
return
|
|
207
|
+
}
|
|
169
208
|
saving.value = true
|
|
170
209
|
try {
|
|
171
210
|
await store.update({
|
|
@@ -185,6 +224,10 @@ async function save() {
|
|
|
185
224
|
storeAgentContext: draft.storeAgentContext,
|
|
186
225
|
artifactRetentionDays: draft.artifactRetentionDays,
|
|
187
226
|
kaizenEnabled: draft.kaizenEnabled,
|
|
227
|
+
reviewFrictionMode: draft.reviewFrictionMode,
|
|
228
|
+
reviewFrictionWarnCount: draft.reviewFrictionWarnCount,
|
|
229
|
+
reviewFrictionBlockCount: blockCount,
|
|
230
|
+
reviewFrictionBlockStuckMinutes: blockStuckMinutes,
|
|
188
231
|
})
|
|
189
232
|
toast.add({
|
|
190
233
|
title: t('settings.workspaceSettings.toast.saved'),
|
|
@@ -288,6 +331,80 @@ async function save() {
|
|
|
288
331
|
</div>
|
|
289
332
|
</section>
|
|
290
333
|
|
|
334
|
+
<!-- Review-debt friction on task creation -->
|
|
335
|
+
<section class="space-y-2">
|
|
336
|
+
<h3 class="text-sm font-semibold text-slate-200">
|
|
337
|
+
{{ t('settings.workspaceSettings.reviewFriction.heading') }}
|
|
338
|
+
</h3>
|
|
339
|
+
<p class="text-[11px] text-slate-400">
|
|
340
|
+
{{ t('settings.workspaceSettings.reviewFriction.body') }}
|
|
341
|
+
</p>
|
|
342
|
+
<label class="block w-64">
|
|
343
|
+
<span class="mb-1 block text-[10px] uppercase tracking-wide text-slate-500">{{
|
|
344
|
+
t('settings.workspaceSettings.reviewFriction.mode')
|
|
345
|
+
}}</span>
|
|
346
|
+
<USelect
|
|
347
|
+
v-model="draft.reviewFrictionMode"
|
|
348
|
+
:items="REVIEW_FRICTION_MODES"
|
|
349
|
+
value-key="value"
|
|
350
|
+
size="sm"
|
|
351
|
+
class="w-full"
|
|
352
|
+
/>
|
|
353
|
+
</label>
|
|
354
|
+
|
|
355
|
+
<label v-if="draft.reviewFrictionMode !== 'off'" class="block w-48">
|
|
356
|
+
<span class="mb-1 block text-[10px] uppercase tracking-wide text-slate-500">
|
|
357
|
+
{{ t('settings.workspaceSettings.reviewFriction.warnCount') }}
|
|
358
|
+
</span>
|
|
359
|
+
<UInput
|
|
360
|
+
v-model.number="draft.reviewFrictionWarnCount"
|
|
361
|
+
type="number"
|
|
362
|
+
:min="1"
|
|
363
|
+
size="sm"
|
|
364
|
+
/>
|
|
365
|
+
</label>
|
|
366
|
+
|
|
367
|
+
<div v-if="draft.reviewFrictionMode === 'enforce'" class="space-y-2">
|
|
368
|
+
<p class="text-[11px] text-slate-400">
|
|
369
|
+
{{ t('settings.workspaceSettings.reviewFriction.enforceHint') }}
|
|
370
|
+
</p>
|
|
371
|
+
<label class="flex items-center gap-2">
|
|
372
|
+
<USwitch v-model="draft.reviewFrictionBlockCountEnabled" size="sm" />
|
|
373
|
+
<span class="text-[13px] text-slate-300">{{
|
|
374
|
+
t('settings.workspaceSettings.reviewFriction.blockCountToggle')
|
|
375
|
+
}}</span>
|
|
376
|
+
</label>
|
|
377
|
+
<label v-if="draft.reviewFrictionBlockCountEnabled" class="block w-48">
|
|
378
|
+
<span class="mb-1 block text-[10px] uppercase tracking-wide text-slate-500">
|
|
379
|
+
{{ t('settings.workspaceSettings.reviewFriction.blockCount') }}
|
|
380
|
+
</span>
|
|
381
|
+
<UInput
|
|
382
|
+
v-model.number="draft.reviewFrictionBlockCount"
|
|
383
|
+
type="number"
|
|
384
|
+
:min="1"
|
|
385
|
+
size="sm"
|
|
386
|
+
/>
|
|
387
|
+
</label>
|
|
388
|
+
<label class="flex items-center gap-2">
|
|
389
|
+
<USwitch v-model="draft.reviewFrictionBlockStuckEnabled" size="sm" />
|
|
390
|
+
<span class="text-[13px] text-slate-300">{{
|
|
391
|
+
t('settings.workspaceSettings.reviewFriction.blockStuckToggle')
|
|
392
|
+
}}</span>
|
|
393
|
+
</label>
|
|
394
|
+
<label v-if="draft.reviewFrictionBlockStuckEnabled" class="block w-48">
|
|
395
|
+
<span class="mb-1 block text-[10px] uppercase tracking-wide text-slate-500">
|
|
396
|
+
{{ t('settings.workspaceSettings.reviewFriction.blockStuckMinutes') }}
|
|
397
|
+
</span>
|
|
398
|
+
<UInput
|
|
399
|
+
v-model.number="draft.reviewFrictionBlockStuckMinutes"
|
|
400
|
+
type="number"
|
|
401
|
+
:min="1"
|
|
402
|
+
size="sm"
|
|
403
|
+
/>
|
|
404
|
+
</label>
|
|
405
|
+
</div>
|
|
406
|
+
</section>
|
|
407
|
+
|
|
291
408
|
<!-- Agent observability -->
|
|
292
409
|
<section class="space-y-2">
|
|
293
410
|
<h3 class="text-sm font-semibold text-slate-200">
|
|
@@ -54,6 +54,7 @@ export function boardApi({ send, ws }: ApiContext) {
|
|
|
54
54
|
pipelineId?: string
|
|
55
55
|
agentConfig?: Record<string, string>
|
|
56
56
|
technical?: boolean
|
|
57
|
+
acknowledgeReviewDebt?: boolean
|
|
57
58
|
},
|
|
58
59
|
) => send(addTaskContract, { pathPrefix: ws(workspaceId), pathParams: { blockId }, body }),
|
|
59
60
|
|
|
@@ -166,6 +166,18 @@ const CONFLICT_INFO: Record<Exclude<ConflictReason, BespokeConflictReason>, Conf
|
|
|
166
166
|
run: (ui) => ui.openGitHub(),
|
|
167
167
|
},
|
|
168
168
|
},
|
|
169
|
+
// Opt-in review-debt friction. In the normal task-create flow AddTaskModal intercepts these
|
|
170
|
+
// 409s and opens the friction dialog (which can retry with an acknowledgement), so these entries
|
|
171
|
+
// are the last-resort toast fallback for any OTHER caller — a generic, param-free title +
|
|
172
|
+
// description reusing the dialog's own `errors.reviewFriction.*` namespace.
|
|
173
|
+
review_debt_warn: {
|
|
174
|
+
titleKey: 'errors.reviewFriction.warnTitle',
|
|
175
|
+
descriptionKey: 'errors.reviewFriction.warnToast',
|
|
176
|
+
},
|
|
177
|
+
review_debt_blocked: {
|
|
178
|
+
titleKey: 'errors.reviewFriction.blockedTitle',
|
|
179
|
+
descriptionKey: 'errors.reviewFriction.blockedToast',
|
|
180
|
+
},
|
|
169
181
|
}
|
|
170
182
|
|
|
171
183
|
/**
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { computed } from 'vue'
|
|
2
|
+
import { assessReviewFriction } from '@cat-factory/contracts'
|
|
3
|
+
import { useNotificationsStore } from '~/stores/notifications'
|
|
4
|
+
import { useWorkspaceSettingsStore } from '~/stores/workspaceSettings'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The client-side review-debt verdict, computed from the SAME pure `assessReviewFriction` the
|
|
8
|
+
* backend enforces with, over the workspace snapshot's open notifications + settings. Lets the
|
|
9
|
+
* add-task affordances pre-warn (a debt badge) BEFORE a create is attempted, so the friction
|
|
10
|
+
* dialog is rarely a surprise. The server stays the authority — this is a hint only. See
|
|
11
|
+
* backend/docs/review-debt-friction.md.
|
|
12
|
+
*/
|
|
13
|
+
export function useReviewDebt() {
|
|
14
|
+
const notifications = useNotificationsStore()
|
|
15
|
+
const settings = useWorkspaceSettingsStore()
|
|
16
|
+
const verdict = computed(() =>
|
|
17
|
+
assessReviewFriction(notifications.open, settings.settings, Date.now()),
|
|
18
|
+
)
|
|
19
|
+
const active = computed(() => verdict.value.kind !== 'ok')
|
|
20
|
+
const debtCount = computed(() => (verdict.value.kind === 'ok' ? 0 : verdict.value.debt.length))
|
|
21
|
+
const blocked = computed(() => verdict.value.kind === 'block')
|
|
22
|
+
return { verdict, active, debtCount, blocked }
|
|
23
|
+
}
|
package/app/pages/index.vue
CHANGED
|
@@ -17,6 +17,7 @@ import DecisionModal from '~/components/panels/DecisionModal.vue'
|
|
|
17
17
|
import AgentStepDetail from '~/components/panels/AgentStepDetail.vue'
|
|
18
18
|
import StepResultViewHost from '~/components/panels/StepResultViewHost.vue'
|
|
19
19
|
import AddTaskModal from '~/components/board/AddTaskModal.vue'
|
|
20
|
+
import ReviewFrictionDialog from '~/components/board/ReviewFrictionDialog.vue'
|
|
20
21
|
import CreateInitiativeModal from '~/components/board/CreateInitiativeModal.vue'
|
|
21
22
|
import GitHubOnboarding from '~/components/github/GitHubOnboarding.vue'
|
|
22
23
|
import CommandBar from '~/components/layout/CommandBar.vue'
|
|
@@ -377,6 +378,7 @@ watch(
|
|
|
377
378
|
<AgentStepDetail />
|
|
378
379
|
<StepResultViewHost />
|
|
379
380
|
<AddTaskModal />
|
|
381
|
+
<ReviewFrictionDialog v-if="ui.reviewFrictionContext" />
|
|
380
382
|
<CreateInitiativeModal />
|
|
381
383
|
<CommandBar />
|
|
382
384
|
<PersonalCredentialModal />
|
|
@@ -73,6 +73,9 @@ export function createBoardMutations(ctx: BoardWriteContext) {
|
|
|
73
73
|
agentConfig?: Record<string, string>
|
|
74
74
|
fragmentIds?: string[]
|
|
75
75
|
technical?: boolean
|
|
76
|
+
// Opt-in review-debt friction: set on the retry after the human confirms the friction
|
|
77
|
+
// dialog, so a soft `review_debt_warn` 409 is tunnelled through (never a hard block).
|
|
78
|
+
acknowledgeReviewDebt?: boolean
|
|
76
79
|
},
|
|
77
80
|
): Promise<Block | undefined> {
|
|
78
81
|
if (!getBlock(containerId)) return
|
|
@@ -90,6 +93,7 @@ export function createBoardMutations(ctx: BoardWriteContext) {
|
|
|
90
93
|
// when a caller doesn't manage fragments at all (then the backend seeds from the service).
|
|
91
94
|
...(options?.fragmentIds !== undefined ? { fragmentIds: options.fragmentIds } : {}),
|
|
92
95
|
...(options?.technical ? { technical: true } : {}),
|
|
96
|
+
...(options?.acknowledgeReviewDebt ? { acknowledgeReviewDebt: true } : {}),
|
|
93
97
|
})
|
|
94
98
|
upsert(block)
|
|
95
99
|
return block
|
package/app/stores/ui/modals.ts
CHANGED
|
@@ -25,6 +25,29 @@ export interface K3sSetupPrefill {
|
|
|
25
25
|
insecureSkipTlsVerify?: boolean
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
/** One task waiting on human review, as carried on a review-debt friction 409's details. */
|
|
29
|
+
export interface ReviewDebtRow {
|
|
30
|
+
blockId: string
|
|
31
|
+
/** The task's title, joined in server-side; null when it couldn't be resolved. */
|
|
32
|
+
title: string | null
|
|
33
|
+
/** How long the task has been waiting on review, in minutes. */
|
|
34
|
+
waitingMinutes: number
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** The context a review-debt friction dialog renders + acts on (from the parsed 409). */
|
|
38
|
+
export interface ReviewFrictionModalContext {
|
|
39
|
+
/** `warn` = soft friction (the human may proceed); `blocked` = hard block (they may not). */
|
|
40
|
+
kind: 'warn' | 'blocked'
|
|
41
|
+
/** Which hard trigger fired (`count` / `stuck`), for the blocked-tier message. */
|
|
42
|
+
reason?: 'count' | 'stuck'
|
|
43
|
+
/** The count / stuck-minutes threshold that fired, for the message. */
|
|
44
|
+
threshold?: number | null
|
|
45
|
+
/** The waiting tasks, worst-first, each deep-linkable to its block. */
|
|
46
|
+
debt: ReviewDebtRow[]
|
|
47
|
+
/** Retry the create with `acknowledgeReviewDebt` — present only for the soft `warn` tier. */
|
|
48
|
+
onConfirm: (() => void) | null
|
|
49
|
+
}
|
|
50
|
+
|
|
28
51
|
/** Clears both hub came-from markers; injected into the slices whose `open*` handlers reset them. */
|
|
29
52
|
type ResetHubReturn = () => void
|
|
30
53
|
|
|
@@ -167,6 +190,14 @@ function createDocumentTaskModals(resetHubReturn: ResetHubReturn) {
|
|
|
167
190
|
// linked context). The user still confirms pipeline / preset before adding.
|
|
168
191
|
const addTaskPrefill = ref<AddTaskPrefill | null>(null)
|
|
169
192
|
|
|
193
|
+
// Review-debt friction dialog: opened when a task-create request is refused by the opt-in
|
|
194
|
+
// friction gate (`review_debt_warn` / `review_debt_blocked` 409). Carries the parsed conflict
|
|
195
|
+
// details the backend supplied (the waiting tasks + the trigger) so the dialog can list exactly
|
|
196
|
+
// what is in review, and — for the soft `warn` tier — an `onConfirm` the "Create anyway" button
|
|
197
|
+
// runs to retry the create with `acknowledgeReviewDebt`. Null when closed. See
|
|
198
|
+
// backend/docs/review-debt-friction.md.
|
|
199
|
+
const reviewFrictionContext = ref<ReviewFrictionModalContext | null>(null)
|
|
200
|
+
|
|
170
201
|
// Add-recurring-pipeline modal: the service frame a new recurring pipeline is
|
|
171
202
|
// being added to, or null when closed (mirrors the add-task flow — a button on
|
|
172
203
|
// the frame opens it, scoped to that frame).
|
|
@@ -232,6 +263,12 @@ function createDocumentTaskModals(resetHubReturn: ResetHubReturn) {
|
|
|
232
263
|
addTaskContainerId.value = null
|
|
233
264
|
addTaskPrefill.value = null
|
|
234
265
|
}
|
|
266
|
+
function openReviewFriction(ctx: ReviewFrictionModalContext) {
|
|
267
|
+
reviewFrictionContext.value = ctx
|
|
268
|
+
}
|
|
269
|
+
function closeReviewFriction() {
|
|
270
|
+
reviewFrictionContext.value = null
|
|
271
|
+
}
|
|
235
272
|
function openAddRecurring(frameId: string) {
|
|
236
273
|
addRecurringFrameId.value = frameId
|
|
237
274
|
}
|
|
@@ -254,6 +291,7 @@ function createDocumentTaskModals(resetHubReturn: ResetHubReturn) {
|
|
|
254
291
|
taskImport,
|
|
255
292
|
addTaskContainerId,
|
|
256
293
|
addTaskPrefill,
|
|
294
|
+
reviewFrictionContext,
|
|
257
295
|
addRecurringFrameId,
|
|
258
296
|
createInitiativeFrameId,
|
|
259
297
|
openDocumentConnect,
|
|
@@ -270,6 +308,8 @@ function createDocumentTaskModals(resetHubReturn: ResetHubReturn) {
|
|
|
270
308
|
closeTaskImport,
|
|
271
309
|
openAddTask,
|
|
272
310
|
closeAddTask,
|
|
311
|
+
openReviewFriction,
|
|
312
|
+
closeReviewFriction,
|
|
273
313
|
openAddRecurring,
|
|
274
314
|
closeAddRecurring,
|
|
275
315
|
openCreateInitiative,
|
|
@@ -13,6 +13,10 @@ const DEFAULTS: WorkspaceSettings = {
|
|
|
13
13
|
artifactRetentionDays: 14,
|
|
14
14
|
kaizenEnabled: true,
|
|
15
15
|
delegateAgentsToRunnerPool: false,
|
|
16
|
+
reviewFrictionMode: 'off',
|
|
17
|
+
reviewFrictionWarnCount: 3,
|
|
18
|
+
reviewFrictionBlockCount: null,
|
|
19
|
+
reviewFrictionBlockStuckMinutes: null,
|
|
16
20
|
spendCurrency: null,
|
|
17
21
|
spendMonthlyLimit: null,
|
|
18
22
|
}
|
package/app/types/domain.ts
CHANGED
package/i18n/locales/de.json
CHANGED
|
@@ -738,6 +738,23 @@
|
|
|
738
738
|
"review": "Review",
|
|
739
739
|
"ralph": "Ralph-Schleife"
|
|
740
740
|
},
|
|
741
|
+
"reviewFriction": {
|
|
742
|
+
"heading": "Review-Rückstau-Bremse",
|
|
743
|
+
"body": "Erschwert das Anlegen neuer Aufgaben, solange fertige Arbeit auf die menschliche Prüfung wartet. Standardmäßig aus. „Warnen“ fügt eine Bestätigung hinzu; „Erzwingen“ verweigert das Anlegen ab einem harten Limit ganz.",
|
|
744
|
+
"mode": "Modus",
|
|
745
|
+
"modes": {
|
|
746
|
+
"off": "Aus",
|
|
747
|
+
"warn": "Warnen (Bestätigung nötig)",
|
|
748
|
+
"enforce": "Erzwingen (harte Sperre)"
|
|
749
|
+
},
|
|
750
|
+
"warnCount": "Warnen ab (Aufgaben in Prüfung)",
|
|
751
|
+
"enforceHint": "„Erzwingen“ verweigert das Anlegen von Aufgaben. Aktiviere unten mindestens einen harten Auslöser.",
|
|
752
|
+
"blockCountToggle": "Sperren, wenn zu viele Aufgaben in Prüfung sind",
|
|
753
|
+
"blockCount": "Sperren ab (Aufgaben in Prüfung)",
|
|
754
|
+
"blockStuckToggle": "Sperren, wenn eine Aufgabe zu lange wartet",
|
|
755
|
+
"blockStuckMinutes": "Sperren nach (Minuten Wartezeit)",
|
|
756
|
+
"needsTrigger": "Der Modus „Erzwingen“ benötigt mindestens einen aktiven harten Auslöser (eine Anzahl oder eine Wartezeit)."
|
|
757
|
+
},
|
|
741
758
|
"observability": {
|
|
742
759
|
"heading": "Agenten-Observability",
|
|
743
760
|
"body": "Speichere den vollständigen Kontext, der jedem Agenten bereitgestellt wird: die zusammengesetzten Prompts, die eingefügten Best-Practice-Fragmente und den vollständigen Inhalt der in seinen Container injizierten Dateien, sodass er später in der Observability-Ansicht inspiziert werden kann. Die Inhalte werden für denselben Zeitraum wie die LLM-Telemetrie pro Aufruf aufbewahrt. Deaktivieren, um die Speicherung zu stoppen (bestehende Snapshots werden durch die Aufbewahrung bereinigt).",
|
|
@@ -4060,6 +4077,22 @@
|
|
|
4060
4077
|
"mergeFailed": "Zusammenführen fehlgeschlagen",
|
|
4061
4078
|
"restartFailed": "Neustart fehlgeschlagen"
|
|
4062
4079
|
},
|
|
4080
|
+
"reviewFriction": {
|
|
4081
|
+
"warnTitle": "Aufgaben warten auf Prüfung",
|
|
4082
|
+
"blockedTitle": "Zu viele Aufgaben warten auf Prüfung",
|
|
4083
|
+
"warnToast": "Einige Aufgaben warten auf die menschliche Prüfung. Prüfe sie, bevor du mehr Arbeit anlegst.",
|
|
4084
|
+
"blockedToast": "Das Anlegen von Aufgaben ist gesperrt, bis der Prüf-Rückstau abgebaut ist.",
|
|
4085
|
+
"warnBody": "{count} Aufgabe(n) warten auf die menschliche Prüfung. Prüfe sie, bevor du mehr Arbeit anlegst.",
|
|
4086
|
+
"blockedCountBody": "Anlegen gesperrt: {count} Aufgabe(n) warten auf die menschliche Prüfung (Limit {threshold}). Baue zuerst den Prüf-Rückstau ab.",
|
|
4087
|
+
"blockedStuckBody": "Anlegen gesperrt: Eine Aufgabe wartet seit über {minutes} Minute(n) auf die menschliche Prüfung. Baue zuerst den Prüf-Rückstau ab.",
|
|
4088
|
+
"waitingHeading": "Warten auf Prüfung",
|
|
4089
|
+
"waiting": "{minutes} Min. Wartezeit",
|
|
4090
|
+
"untitled": "Aufgabe ohne Titel",
|
|
4091
|
+
"close": "Schließen",
|
|
4092
|
+
"createAnyway": "Trotzdem anlegen",
|
|
4093
|
+
"goReview": "Zur Prüfung",
|
|
4094
|
+
"badge": "{count} Aufgabe(n) warten auf Prüfung"
|
|
4095
|
+
},
|
|
4063
4096
|
"conflict": {
|
|
4064
4097
|
"title": {
|
|
4065
4098
|
"dependencies_unmet": "Durch Abhängigkeiten blockiert",
|
package/i18n/locales/en.json
CHANGED
|
@@ -493,6 +493,22 @@
|
|
|
493
493
|
"mergeFailed": "Failed to merge",
|
|
494
494
|
"restartFailed": "Failed to restart"
|
|
495
495
|
},
|
|
496
|
+
"reviewFriction": {
|
|
497
|
+
"warnTitle": "Tasks waiting on review",
|
|
498
|
+
"blockedTitle": "Too many tasks waiting on review",
|
|
499
|
+
"warnToast": "Some tasks are waiting on human review. Consider reviewing them before creating more work.",
|
|
500
|
+
"blockedToast": "Task creation is blocked until the review queue is worked down.",
|
|
501
|
+
"warnBody": "{count} task(s) are waiting on human review. Consider reviewing them before creating more work.",
|
|
502
|
+
"blockedCountBody": "Task creation is blocked: {count} task(s) are waiting on human review (limit {threshold}). Work down the review queue first.",
|
|
503
|
+
"blockedStuckBody": "Task creation is blocked: a task has been waiting on human review for over {minutes} minute(s). Work down the review queue first.",
|
|
504
|
+
"waitingHeading": "Waiting on review",
|
|
505
|
+
"waiting": "{minutes} min waiting",
|
|
506
|
+
"untitled": "Untitled task",
|
|
507
|
+
"close": "Close",
|
|
508
|
+
"createAnyway": "Create anyway",
|
|
509
|
+
"goReview": "Go review",
|
|
510
|
+
"badge": "{count} task(s) waiting on review"
|
|
511
|
+
},
|
|
496
512
|
"conflict": {
|
|
497
513
|
"title": {
|
|
498
514
|
"dependencies_unmet": "Blocked by dependencies",
|
|
@@ -2757,6 +2773,23 @@
|
|
|
2757
2773
|
"review": "review",
|
|
2758
2774
|
"ralph": "Ralph loop"
|
|
2759
2775
|
},
|
|
2776
|
+
"reviewFriction": {
|
|
2777
|
+
"heading": "Review-debt friction",
|
|
2778
|
+
"body": "Discourage authoring new tasks while finished work waits on human review. Off by default. Warn adds a confirm-to-proceed step; Enforce also refuses task creation outright past a hard limit.",
|
|
2779
|
+
"mode": "Mode",
|
|
2780
|
+
"modes": {
|
|
2781
|
+
"off": "Off",
|
|
2782
|
+
"warn": "Warn (confirm to proceed)",
|
|
2783
|
+
"enforce": "Enforce (hard block)"
|
|
2784
|
+
},
|
|
2785
|
+
"warnCount": "Warn at (tasks in review)",
|
|
2786
|
+
"enforceHint": "Enforce refuses task creation. Enable at least one hard trigger below.",
|
|
2787
|
+
"blockCountToggle": "Block when too many tasks are in review",
|
|
2788
|
+
"blockCount": "Block at (tasks in review)",
|
|
2789
|
+
"blockStuckToggle": "Block when a task has waited too long",
|
|
2790
|
+
"blockStuckMinutes": "Block after (minutes waiting)",
|
|
2791
|
+
"needsTrigger": "Enforce mode needs at least one hard trigger enabled (a count or a wait time)."
|
|
2792
|
+
},
|
|
2760
2793
|
"observability": {
|
|
2761
2794
|
"heading": "Agent observability",
|
|
2762
2795
|
"body": "Store the complete context provided to each agent: the composed prompts, the best-practice fragments folded in, and the full content of the files injected into its container, so it can be inspected later in the observability view. The bodies are kept for the same window as the per-call LLM telemetry. Turn off to stop storing it (existing snapshots are pruned by retention).",
|
package/i18n/locales/es.json
CHANGED
|
@@ -457,6 +457,22 @@
|
|
|
457
457
|
"mergeFailed": "No se pudo fusionar",
|
|
458
458
|
"restartFailed": "No se pudo reiniciar"
|
|
459
459
|
},
|
|
460
|
+
"reviewFriction": {
|
|
461
|
+
"warnTitle": "Tareas esperando revisión",
|
|
462
|
+
"blockedTitle": "Demasiadas tareas esperando revisión",
|
|
463
|
+
"warnToast": "Algunas tareas esperan revisión humana. Considera revisarlas antes de crear más trabajo.",
|
|
464
|
+
"blockedToast": "La creación de tareas está bloqueada hasta reducir la cola de revisión.",
|
|
465
|
+
"warnBody": "{count} tarea(s) esperan revisión humana. Considera revisarlas antes de crear más trabajo.",
|
|
466
|
+
"blockedCountBody": "Creación bloqueada: {count} tarea(s) esperan revisión humana (límite {threshold}). Reduce primero la cola de revisión.",
|
|
467
|
+
"blockedStuckBody": "Creación bloqueada: una tarea lleva más de {minutes} minuto(s) esperando revisión humana. Reduce primero la cola de revisión.",
|
|
468
|
+
"waitingHeading": "Esperando revisión",
|
|
469
|
+
"waiting": "{minutes} min esperando",
|
|
470
|
+
"untitled": "Tarea sin título",
|
|
471
|
+
"close": "Cerrar",
|
|
472
|
+
"createAnyway": "Crear de todos modos",
|
|
473
|
+
"goReview": "Ir a revisar",
|
|
474
|
+
"badge": "{count} tarea(s) esperando revisión"
|
|
475
|
+
},
|
|
460
476
|
"conflict": {
|
|
461
477
|
"title": {
|
|
462
478
|
"dependencies_unmet": "Bloqueado por dependencias",
|
|
@@ -2569,6 +2585,23 @@
|
|
|
2569
2585
|
"review": "revisión",
|
|
2570
2586
|
"ralph": "Bucle Ralph"
|
|
2571
2587
|
},
|
|
2588
|
+
"reviewFriction": {
|
|
2589
|
+
"heading": "Fricción por revisión pendiente",
|
|
2590
|
+
"body": "Desalienta crear tareas nuevas mientras el trabajo terminado espera revisión humana. Desactivado por defecto. «Avisar» añade una confirmación; «Aplicar» rechaza la creación al superar un límite estricto.",
|
|
2591
|
+
"mode": "Modo",
|
|
2592
|
+
"modes": {
|
|
2593
|
+
"off": "Desactivado",
|
|
2594
|
+
"warn": "Avisar (confirmar para continuar)",
|
|
2595
|
+
"enforce": "Aplicar (bloqueo estricto)"
|
|
2596
|
+
},
|
|
2597
|
+
"warnCount": "Avisar a partir de (tareas en revisión)",
|
|
2598
|
+
"enforceHint": "«Aplicar» rechaza la creación de tareas. Activa al menos un disparador estricto abajo.",
|
|
2599
|
+
"blockCountToggle": "Bloquear cuando haya demasiadas tareas en revisión",
|
|
2600
|
+
"blockCount": "Bloquear a partir de (tareas en revisión)",
|
|
2601
|
+
"blockStuckToggle": "Bloquear cuando una tarea lleve esperando demasiado",
|
|
2602
|
+
"blockStuckMinutes": "Bloquear tras (minutos de espera)",
|
|
2603
|
+
"needsTrigger": "El modo «Aplicar» necesita al menos un disparador estricto activo (un recuento o un tiempo de espera)."
|
|
2604
|
+
},
|
|
2572
2605
|
"observability": {
|
|
2573
2606
|
"heading": "Observabilidad del agente",
|
|
2574
2607
|
"body": "Almacena el contexto completo proporcionado a cada agente: los prompts compuestos, los fragmentos de buenas prácticas incorporados y el contenido íntegro de los archivos inyectados en su contenedor, para poder inspeccionarlo después en la vista de observabilidad. Los cuerpos se conservan durante la misma ventana que la telemetría de LLM por llamada. Desactívalo para dejar de almacenarlo (las instantáneas existentes se eliminan por retención).",
|
package/i18n/locales/fr.json
CHANGED
|
@@ -457,6 +457,22 @@
|
|
|
457
457
|
"mergeFailed": "Échec de la fusion",
|
|
458
458
|
"restartFailed": "Échec du redémarrage"
|
|
459
459
|
},
|
|
460
|
+
"reviewFriction": {
|
|
461
|
+
"warnTitle": "Tâches en attente de revue",
|
|
462
|
+
"blockedTitle": "Trop de tâches en attente de revue",
|
|
463
|
+
"warnToast": "Des tâches attendent une revue humaine. Pensez à les revoir avant de créer plus de travail.",
|
|
464
|
+
"blockedToast": "La création de tâches est bloquée jusqu’à résorption de la file de revue.",
|
|
465
|
+
"warnBody": "{count} tâche(s) attendent une revue humaine. Pensez à les revoir avant de créer plus de travail.",
|
|
466
|
+
"blockedCountBody": "Création bloquée : {count} tâche(s) attendent une revue humaine (limite {threshold}). Résorbez d’abord la file de revue.",
|
|
467
|
+
"blockedStuckBody": "Création bloquée : une tâche attend une revue humaine depuis plus de {minutes} minute(s). Résorbez d’abord la file de revue.",
|
|
468
|
+
"waitingHeading": "En attente de revue",
|
|
469
|
+
"waiting": "{minutes} min d’attente",
|
|
470
|
+
"untitled": "Tâche sans titre",
|
|
471
|
+
"close": "Fermer",
|
|
472
|
+
"createAnyway": "Créer quand même",
|
|
473
|
+
"goReview": "Aller revoir",
|
|
474
|
+
"badge": "{count} tâche(s) en attente de revue"
|
|
475
|
+
},
|
|
460
476
|
"conflict": {
|
|
461
477
|
"title": {
|
|
462
478
|
"dependencies_unmet": "Bloqué par des dépendances",
|
|
@@ -2569,6 +2585,23 @@
|
|
|
2569
2585
|
"review": "revue",
|
|
2570
2586
|
"ralph": "Boucle Ralph"
|
|
2571
2587
|
},
|
|
2588
|
+
"reviewFriction": {
|
|
2589
|
+
"heading": "Friction de dette de revue",
|
|
2590
|
+
"body": "Décourage la création de nouvelles tâches tant que du travail terminé attend une revue humaine. Désactivé par défaut. « Avertir » ajoute une confirmation ; « Imposer » refuse la création au-delà d’une limite stricte.",
|
|
2591
|
+
"mode": "Mode",
|
|
2592
|
+
"modes": {
|
|
2593
|
+
"off": "Désactivé",
|
|
2594
|
+
"warn": "Avertir (confirmer pour continuer)",
|
|
2595
|
+
"enforce": "Imposer (blocage strict)"
|
|
2596
|
+
},
|
|
2597
|
+
"warnCount": "Avertir à partir de (tâches en revue)",
|
|
2598
|
+
"enforceHint": "« Imposer » refuse la création de tâches. Activez au moins un déclencheur strict ci-dessous.",
|
|
2599
|
+
"blockCountToggle": "Bloquer quand trop de tâches sont en revue",
|
|
2600
|
+
"blockCount": "Bloquer à partir de (tâches en revue)",
|
|
2601
|
+
"blockStuckToggle": "Bloquer quand une tâche attend depuis trop longtemps",
|
|
2602
|
+
"blockStuckMinutes": "Bloquer après (minutes d’attente)",
|
|
2603
|
+
"needsTrigger": "Le mode « Imposer » nécessite au moins un déclencheur strict activé (un nombre ou un temps d’attente)."
|
|
2604
|
+
},
|
|
2572
2605
|
"observability": {
|
|
2573
2606
|
"heading": "Observabilité de l'agent",
|
|
2574
2607
|
"body": "Stockez le contexte complet fourni à chaque agent : les prompts composés, les fragments de bonnes pratiques intégrés et le contenu intégral des fichiers injectés dans son conteneur, afin de pouvoir l'inspecter plus tard dans la vue d'observabilité. Les corps sont conservés pendant la même fenêtre que la télémétrie LLM par appel. Désactivez pour cesser de le stocker (les instantanés existants sont supprimés par la rétention).",
|
package/i18n/locales/he.json
CHANGED
|
@@ -457,6 +457,22 @@
|
|
|
457
457
|
"mergeFailed": "המיזוג נכשל",
|
|
458
458
|
"restartFailed": "ההפעלה מחדש נכשלה"
|
|
459
459
|
},
|
|
460
|
+
"reviewFriction": {
|
|
461
|
+
"warnTitle": "משימות ממתינות לסקירה",
|
|
462
|
+
"blockedTitle": "יותר מדי משימות ממתינות לסקירה",
|
|
463
|
+
"warnToast": "כמה משימות ממתינות לסקירה אנושית. שקול לסקור אותן לפני יצירת עבודה נוספת.",
|
|
464
|
+
"blockedToast": "יצירת משימות חסומה עד לצמצום תור הסקירה.",
|
|
465
|
+
"warnBody": "{count} משימות ממתינות לסקירה אנושית. שקול לסקור אותן לפני יצירת עבודה נוספת.",
|
|
466
|
+
"blockedCountBody": "היצירה חסומה: {count} משימות ממתינות לסקירה אנושית (מגבלה {threshold}). צמצם תחילה את תור הסקירה.",
|
|
467
|
+
"blockedStuckBody": "היצירה חסומה: משימה ממתינה לסקירה אנושית יותר מ־{minutes} דקות. צמצם תחילה את תור הסקירה.",
|
|
468
|
+
"waitingHeading": "ממתין לסקירה",
|
|
469
|
+
"waiting": "{minutes} דק׳ בהמתנה",
|
|
470
|
+
"untitled": "משימה ללא כותרת",
|
|
471
|
+
"close": "סגור",
|
|
472
|
+
"createAnyway": "צור בכל זאת",
|
|
473
|
+
"goReview": "עבור לסקירה",
|
|
474
|
+
"badge": "{count} משימות ממתינות לסקירה"
|
|
475
|
+
},
|
|
460
476
|
"conflict": {
|
|
461
477
|
"title": {
|
|
462
478
|
"dependencies_unmet": "חסום על ידי תלויות",
|
|
@@ -2690,6 +2706,23 @@
|
|
|
2690
2706
|
"review": "סקירה",
|
|
2691
2707
|
"ralph": "לולאת Ralph"
|
|
2692
2708
|
},
|
|
2709
|
+
"reviewFriction": {
|
|
2710
|
+
"heading": "חיכוך חוב סקירה",
|
|
2711
|
+
"body": "מרתיע מיצירת משימות חדשות בזמן שעבודה שהושלמה ממתינה לסקירה אנושית. כבוי כברירת מחדל. „אזהרה” מוסיפה אישור; „אכיפה” מסרבת ליצירה מעבר לגבול קשיח.",
|
|
2712
|
+
"mode": "מצב",
|
|
2713
|
+
"modes": {
|
|
2714
|
+
"off": "כבוי",
|
|
2715
|
+
"warn": "אזהרה (אישור כדי להמשיך)",
|
|
2716
|
+
"enforce": "אכיפה (חסימה קשיחה)"
|
|
2717
|
+
},
|
|
2718
|
+
"warnCount": "אזהרה החל מ־ (משימות בסקירה)",
|
|
2719
|
+
"enforceHint": "„אכיפה” מסרבת ליצירת משימות. הפעל לפחות טריגר קשיח אחד למטה.",
|
|
2720
|
+
"blockCountToggle": "חסום כשיש יותר מדי משימות בסקירה",
|
|
2721
|
+
"blockCount": "חסום החל מ־ (משימות בסקירה)",
|
|
2722
|
+
"blockStuckToggle": "חסום כשמשימה ממתינה יותר מדי זמן",
|
|
2723
|
+
"blockStuckMinutes": "חסום לאחר (דקות המתנה)",
|
|
2724
|
+
"needsTrigger": "מצב „אכיפה” דורש לפחות טריגר קשיח פעיל אחד (מספר או זמן המתנה)."
|
|
2725
|
+
},
|
|
2693
2726
|
"observability": {
|
|
2694
2727
|
"heading": "תצפיתיות סוכנים",
|
|
2695
2728
|
"body": "אחסן את ההקשר המלא שניתן לכל סוכן: ההנחיות המורכבות, מקטעי שיטות העבודה המומלצות שמשולבים, והתוכן המלא של הקבצים שמוזרקים לקונטיינר שלו, כך שניתן יהיה לבדוק אותו מאוחר יותר בתצוגת התצפיתיות. הגופים נשמרים לאותו חלון כמו טלמטריית ה-LLM לכל קריאה. כבה כדי להפסיק לאחסן אותו (תצלומים קיימים נגזמים לפי תקופת השמירה).",
|
package/i18n/locales/it.json
CHANGED
|
@@ -738,6 +738,23 @@
|
|
|
738
738
|
"review": "revisione",
|
|
739
739
|
"ralph": "Ciclo Ralph"
|
|
740
740
|
},
|
|
741
|
+
"reviewFriction": {
|
|
742
|
+
"heading": "Attrito per revisioni in sospeso",
|
|
743
|
+
"body": "Scoraggia la creazione di nuove attività mentre il lavoro completato attende la revisione umana. Disattivato per impostazione predefinita. «Avvisa» aggiunge una conferma; «Imponi» rifiuta la creazione oltre un limite rigido.",
|
|
744
|
+
"mode": "Modalità",
|
|
745
|
+
"modes": {
|
|
746
|
+
"off": "Disattivato",
|
|
747
|
+
"warn": "Avvisa (conferma per procedere)",
|
|
748
|
+
"enforce": "Imponi (blocco rigido)"
|
|
749
|
+
},
|
|
750
|
+
"warnCount": "Avvisa da (attività in revisione)",
|
|
751
|
+
"enforceHint": "«Imponi» rifiuta la creazione di attività. Attiva almeno un trigger rigido qui sotto.",
|
|
752
|
+
"blockCountToggle": "Blocca quando troppe attività sono in revisione",
|
|
753
|
+
"blockCount": "Blocca da (attività in revisione)",
|
|
754
|
+
"blockStuckToggle": "Blocca quando un’attività attende da troppo tempo",
|
|
755
|
+
"blockStuckMinutes": "Blocca dopo (minuti di attesa)",
|
|
756
|
+
"needsTrigger": "La modalità «Imponi» richiede almeno un trigger rigido attivo (un conteggio o un tempo di attesa)."
|
|
757
|
+
},
|
|
741
758
|
"observability": {
|
|
742
759
|
"heading": "Osservabilita degli agenti",
|
|
743
760
|
"body": "Memorizza il contesto completo fornito a ogni agente: i prompt composti, i frammenti di best practice inclusi e il contenuto completo dei file iniettati nel suo container, cosicche possa essere ispezionato in seguito nella vista di osservabilita. I corpi vengono conservati per la stessa finestra della telemetria LLM per chiamata. Disattiva per interrompere la memorizzazione (gli snapshot esistenti vengono eliminati dalla retention).",
|
|
@@ -4060,6 +4077,22 @@
|
|
|
4060
4077
|
"mergeFailed": "Merge non riuscito",
|
|
4061
4078
|
"restartFailed": "Riavvio non riuscito"
|
|
4062
4079
|
},
|
|
4080
|
+
"reviewFriction": {
|
|
4081
|
+
"warnTitle": "Attività in attesa di revisione",
|
|
4082
|
+
"blockedTitle": "Troppe attività in attesa di revisione",
|
|
4083
|
+
"warnToast": "Alcune attività attendono la revisione umana. Valuta di revisionarle prima di creare altro lavoro.",
|
|
4084
|
+
"blockedToast": "La creazione di attività è bloccata finché non si riduce la coda di revisione.",
|
|
4085
|
+
"warnBody": "{count} attività attendono la revisione umana. Valuta di revisionarle prima di creare altro lavoro.",
|
|
4086
|
+
"blockedCountBody": "Creazione bloccata: {count} attività attendono la revisione umana (limite {threshold}). Riduci prima la coda di revisione.",
|
|
4087
|
+
"blockedStuckBody": "Creazione bloccata: un’attività attende la revisione umana da oltre {minutes} minuto/i. Riduci prima la coda di revisione.",
|
|
4088
|
+
"waitingHeading": "In attesa di revisione",
|
|
4089
|
+
"waiting": "{minutes} min di attesa",
|
|
4090
|
+
"untitled": "Attività senza titolo",
|
|
4091
|
+
"close": "Chiudi",
|
|
4092
|
+
"createAnyway": "Crea comunque",
|
|
4093
|
+
"goReview": "Vai a revisionare",
|
|
4094
|
+
"badge": "{count} attività in attesa di revisione"
|
|
4095
|
+
},
|
|
4063
4096
|
"conflict": {
|
|
4064
4097
|
"title": {
|
|
4065
4098
|
"dependencies_unmet": "Bloccato dalle dipendenze",
|
package/i18n/locales/ja.json
CHANGED
|
@@ -457,6 +457,22 @@
|
|
|
457
457
|
"mergeFailed": "マージに失敗しました",
|
|
458
458
|
"restartFailed": "再起動に失敗しました"
|
|
459
459
|
},
|
|
460
|
+
"reviewFriction": {
|
|
461
|
+
"warnTitle": "レビュー待ちのタスク",
|
|
462
|
+
"blockedTitle": "レビュー待ちのタスクが多すぎます",
|
|
463
|
+
"warnToast": "一部のタスクが人によるレビューを待っています。新しい作業を作成する前にレビューを検討してください。",
|
|
464
|
+
"blockedToast": "レビュー待ち行列が解消されるまで、タスクの作成はブロックされます。",
|
|
465
|
+
"warnBody": "{count} 件のタスクが人によるレビューを待っています。新しい作業を作成する前にレビューを検討してください。",
|
|
466
|
+
"blockedCountBody": "作成がブロックされました:{count} 件のタスクが人によるレビューを待っています(上限 {threshold})。先にレビュー待ち行列を解消してください。",
|
|
467
|
+
"blockedStuckBody": "作成がブロックされました:あるタスクが {minutes} 分以上、人によるレビューを待っています。先にレビュー待ち行列を解消してください。",
|
|
468
|
+
"waitingHeading": "レビュー待ち",
|
|
469
|
+
"waiting": "待機 {minutes} 分",
|
|
470
|
+
"untitled": "無題のタスク",
|
|
471
|
+
"close": "閉じる",
|
|
472
|
+
"createAnyway": "それでも作成",
|
|
473
|
+
"goReview": "レビューへ移動",
|
|
474
|
+
"badge": "{count} 件のタスクがレビュー待ち"
|
|
475
|
+
},
|
|
460
476
|
"conflict": {
|
|
461
477
|
"title": {
|
|
462
478
|
"dependencies_unmet": "依存関係によりブロック中",
|
|
@@ -2691,6 +2707,23 @@
|
|
|
2691
2707
|
"review": "レビュー",
|
|
2692
2708
|
"ralph": "Ralph ループ"
|
|
2693
2709
|
},
|
|
2710
|
+
"reviewFriction": {
|
|
2711
|
+
"heading": "レビュー滞留の摩擦",
|
|
2712
|
+
"body": "完了した作業が人によるレビューを待っている間、新しいタスクの作成を抑制します。既定ではオフ。「警告」は確認ステップを追加し、「強制」は厳格な上限を超えると作成を完全に拒否します。",
|
|
2713
|
+
"mode": "モード",
|
|
2714
|
+
"modes": {
|
|
2715
|
+
"off": "オフ",
|
|
2716
|
+
"warn": "警告(確認して続行)",
|
|
2717
|
+
"enforce": "強制(ハードブロック)"
|
|
2718
|
+
},
|
|
2719
|
+
"warnCount": "警告するしきい値(レビュー中のタスク数)",
|
|
2720
|
+
"enforceHint": "「強制」はタスク作成を拒否します。下で少なくとも1つのハードトリガーを有効にしてください。",
|
|
2721
|
+
"blockCountToggle": "レビュー中のタスクが多すぎる場合にブロック",
|
|
2722
|
+
"blockCount": "ブロックするしきい値(レビュー中のタスク数)",
|
|
2723
|
+
"blockStuckToggle": "タスクの待機が長すぎる場合にブロック",
|
|
2724
|
+
"blockStuckMinutes": "ブロックするまでの時間(待機分数)",
|
|
2725
|
+
"needsTrigger": "「強制」モードには、有効なハードトリガーが少なくとも1つ必要です(件数または待機時間)。"
|
|
2726
|
+
},
|
|
2694
2727
|
"observability": {
|
|
2695
2728
|
"heading": "エージェントの可観測性",
|
|
2696
2729
|
"body": "各エージェントに提供された完全なコンテキストを保存します。構成されたプロンプト、折り込まれたベストプラクティスのフラグメント、コンテナに注入されたファイルの全内容を保存し、後から可観測性ビューで確認できます。本文は呼び出しごとの LLM テレメトリと同じ期間だけ保持されます。オフにすると保存を停止します (既存のスナップショットは保持期限により削除されます)。",
|
package/i18n/locales/pl.json
CHANGED
|
@@ -457,6 +457,22 @@
|
|
|
457
457
|
"mergeFailed": "Nie udało się scalić",
|
|
458
458
|
"restartFailed": "Nie udało się ponownie uruchomić"
|
|
459
459
|
},
|
|
460
|
+
"reviewFriction": {
|
|
461
|
+
"warnTitle": "Zadania czekające na przegląd",
|
|
462
|
+
"blockedTitle": "Zbyt wiele zadań czeka na przegląd",
|
|
463
|
+
"warnToast": "Niektóre zadania czekają na przegląd przez człowieka. Rozważ ich przejrzenie przed tworzeniem kolejnej pracy.",
|
|
464
|
+
"blockedToast": "Tworzenie zadań jest zablokowane do czasu zmniejszenia kolejki przeglądów.",
|
|
465
|
+
"warnBody": "{count} zadań czeka na przegląd przez człowieka. Rozważ ich przejrzenie przed tworzeniem kolejnej pracy.",
|
|
466
|
+
"blockedCountBody": "Tworzenie zablokowane: {count} zadań czeka na przegląd przez człowieka (limit {threshold}). Najpierw zmniejsz kolejkę przeglądów.",
|
|
467
|
+
"blockedStuckBody": "Tworzenie zablokowane: zadanie czeka na przegląd przez człowieka od ponad {minutes} minut(y). Najpierw zmniejsz kolejkę przeglądów.",
|
|
468
|
+
"waitingHeading": "Oczekujące na przegląd",
|
|
469
|
+
"waiting": "{minutes} min oczekiwania",
|
|
470
|
+
"untitled": "Zadanie bez tytułu",
|
|
471
|
+
"close": "Zamknij",
|
|
472
|
+
"createAnyway": "Utwórz mimo to",
|
|
473
|
+
"goReview": "Przejdź do przeglądu",
|
|
474
|
+
"badge": "{count} zadań czeka na przegląd"
|
|
475
|
+
},
|
|
460
476
|
"conflict": {
|
|
461
477
|
"title": {
|
|
462
478
|
"dependencies_unmet": "Zablokowane przez zależności",
|
|
@@ -2569,6 +2585,23 @@
|
|
|
2569
2585
|
"review": "przegląd",
|
|
2570
2586
|
"ralph": "Pętla Ralph"
|
|
2571
2587
|
},
|
|
2588
|
+
"reviewFriction": {
|
|
2589
|
+
"heading": "Hamulec długu przeglądów",
|
|
2590
|
+
"body": "Zniechęca do tworzenia nowych zadań, gdy ukończona praca czeka na przegląd przez człowieka. Domyślnie wyłączone. „Ostrzegaj” dodaje potwierdzenie; „Wymuszaj” całkowicie odmawia utworzenia po przekroczeniu twardego limitu.",
|
|
2591
|
+
"mode": "Tryb",
|
|
2592
|
+
"modes": {
|
|
2593
|
+
"off": "Wyłączone",
|
|
2594
|
+
"warn": "Ostrzegaj (potwierdź, aby kontynuować)",
|
|
2595
|
+
"enforce": "Wymuszaj (twarda blokada)"
|
|
2596
|
+
},
|
|
2597
|
+
"warnCount": "Ostrzegaj od (zadań w przeglądzie)",
|
|
2598
|
+
"enforceHint": "„Wymuszaj” odmawia tworzenia zadań. Włącz poniżej co najmniej jeden twardy wyzwalacz.",
|
|
2599
|
+
"blockCountToggle": "Blokuj, gdy zbyt wiele zadań jest w przeglądzie",
|
|
2600
|
+
"blockCount": "Blokuj od (zadań w przeglądzie)",
|
|
2601
|
+
"blockStuckToggle": "Blokuj, gdy zadanie czeka zbyt długo",
|
|
2602
|
+
"blockStuckMinutes": "Blokuj po (minutach oczekiwania)",
|
|
2603
|
+
"needsTrigger": "Tryb „Wymuszaj” wymaga włączenia co najmniej jednego twardego wyzwalacza (liczby lub czasu oczekiwania)."
|
|
2604
|
+
},
|
|
2572
2605
|
"observability": {
|
|
2573
2606
|
"heading": "Obserwowalność agenta",
|
|
2574
2607
|
"body": "Przechowuj pełny kontekst przekazany każdemu agentowi: złożone prompty, włączone fragmenty dobrych praktyk oraz pełną treść plików wstrzykniętych do jego kontenera, aby można było je później sprawdzić w widoku obserwowalności. Treści są przechowywane przez to samo okno co telemetria LLM dla poszczególnych wywołań. Wyłącz, aby przestać je przechowywać (istniejące migawki są usuwane przez retencję).",
|
package/i18n/locales/tr.json
CHANGED
|
@@ -457,6 +457,22 @@
|
|
|
457
457
|
"mergeFailed": "Birleştirilemedi",
|
|
458
458
|
"restartFailed": "Yeniden başlatılamadı"
|
|
459
459
|
},
|
|
460
|
+
"reviewFriction": {
|
|
461
|
+
"warnTitle": "Görevler incelemeyi bekliyor",
|
|
462
|
+
"blockedTitle": "Çok fazla görev incelemeyi bekliyor",
|
|
463
|
+
"warnToast": "Bazı görevler insan incelemesini bekliyor. Daha fazla iş oluşturmadan önce onları incelemeyi düşünün.",
|
|
464
|
+
"blockedToast": "İnceleme kuyruğu azaltılana kadar görev oluşturma engellendi.",
|
|
465
|
+
"warnBody": "{count} görev insan incelemesini bekliyor. Daha fazla iş oluşturmadan önce onları incelemeyi düşünün.",
|
|
466
|
+
"blockedCountBody": "Oluşturma engellendi: {count} görev insan incelemesini bekliyor (sınır {threshold}). Önce inceleme kuyruğunu azaltın.",
|
|
467
|
+
"blockedStuckBody": "Oluşturma engellendi: bir görev {minutes} dakikadan uzun süredir insan incelemesini bekliyor. Önce inceleme kuyruğunu azaltın.",
|
|
468
|
+
"waitingHeading": "İncelemeyi bekliyor",
|
|
469
|
+
"waiting": "{minutes} dk bekliyor",
|
|
470
|
+
"untitled": "Başlıksız görev",
|
|
471
|
+
"close": "Kapat",
|
|
472
|
+
"createAnyway": "Yine de oluştur",
|
|
473
|
+
"goReview": "İncelemeye git",
|
|
474
|
+
"badge": "{count} görev incelemeyi bekliyor"
|
|
475
|
+
},
|
|
460
476
|
"conflict": {
|
|
461
477
|
"title": {
|
|
462
478
|
"dependencies_unmet": "Bağımlılıklar tarafından engellendi",
|
|
@@ -2691,6 +2707,23 @@
|
|
|
2691
2707
|
"review": "inceleme",
|
|
2692
2708
|
"ralph": "Ralph döngüsü"
|
|
2693
2709
|
},
|
|
2710
|
+
"reviewFriction": {
|
|
2711
|
+
"heading": "İnceleme borcu sürtünmesi",
|
|
2712
|
+
"body": "Tamamlanan iş insan incelemesini beklerken yeni görev oluşturmayı caydırır. Varsayılan olarak kapalı. «Uyar» bir onay adımı ekler; «Zorla» katı bir sınırın ötesinde oluşturmayı tümüyle reddeder.",
|
|
2713
|
+
"mode": "Mod",
|
|
2714
|
+
"modes": {
|
|
2715
|
+
"off": "Kapalı",
|
|
2716
|
+
"warn": "Uyar (devam için onayla)",
|
|
2717
|
+
"enforce": "Zorla (katı engel)"
|
|
2718
|
+
},
|
|
2719
|
+
"warnCount": "Şu sayıda uyar (incelemedeki görevler)",
|
|
2720
|
+
"enforceHint": "«Zorla» görev oluşturmayı reddeder. Aşağıda en az bir katı tetikleyici etkinleştirin.",
|
|
2721
|
+
"blockCountToggle": "İncelemede çok fazla görev olduğunda engelle",
|
|
2722
|
+
"blockCount": "Şu sayıda engelle (incelemedeki görevler)",
|
|
2723
|
+
"blockStuckToggle": "Bir görev çok uzun süre beklediğinde engelle",
|
|
2724
|
+
"blockStuckMinutes": "Şu süreden sonra engelle (dakika bekleme)",
|
|
2725
|
+
"needsTrigger": "«Zorla» modu en az bir etkin katı tetikleyici gerektirir (bir sayı veya bir bekleme süresi)."
|
|
2726
|
+
},
|
|
2694
2727
|
"observability": {
|
|
2695
2728
|
"heading": "Agent gözlemlenebilirliği",
|
|
2696
2729
|
"body": "Her agent'a sağlanan tüm bağlamı saklayın: oluşturulan istemler, içine katlanan en iyi uygulama parçaları ve konteynerine enjekte edilen dosyaların tam içeriği; böylece daha sonra gözlemlenebilirlik görünümünde incelenebilir. Gövdeler, çağrı başına LLM telemetrisi ile aynı süre boyunca tutulur. Saklamayı durdurmak için kapatın (mevcut anlık görüntüler saklama ilkesiyle temizlenir).",
|
package/i18n/locales/uk.json
CHANGED
|
@@ -457,6 +457,22 @@
|
|
|
457
457
|
"mergeFailed": "Не вдалося злити",
|
|
458
458
|
"restartFailed": "Не вдалося перезапустити"
|
|
459
459
|
},
|
|
460
|
+
"reviewFriction": {
|
|
461
|
+
"warnTitle": "Завдання чекають на рев’ю",
|
|
462
|
+
"blockedTitle": "Забагато завдань чекають на рев’ю",
|
|
463
|
+
"warnToast": "Деякі завдання чекають на рев’ю людиною. Розгляньте можливість переглянути їх, перш ніж створювати більше роботи.",
|
|
464
|
+
"blockedToast": "Створення завдань заблоковано, доки не зменшиться черга рев’ю.",
|
|
465
|
+
"warnBody": "{count} завдань(ня) чекають на рев’ю людиною. Розгляньте можливість переглянути їх, перш ніж створювати більше роботи.",
|
|
466
|
+
"blockedCountBody": "Створення заблоковано: {count} завдань(ня) чекають на рев’ю людиною (ліміт {threshold}). Спершу зменшіть чергу рев’ю.",
|
|
467
|
+
"blockedStuckBody": "Створення заблоковано: завдання чекає на рев’ю людиною понад {minutes} хвилин(и). Спершу зменшіть чергу рев’ю.",
|
|
468
|
+
"waitingHeading": "Очікують на рев’ю",
|
|
469
|
+
"waiting": "{minutes} хв очікування",
|
|
470
|
+
"untitled": "Завдання без назви",
|
|
471
|
+
"close": "Закрити",
|
|
472
|
+
"createAnyway": "Усе одно створити",
|
|
473
|
+
"goReview": "Перейти до рев’ю",
|
|
474
|
+
"badge": "{count} завдань(ня) чекають на рев’ю"
|
|
475
|
+
},
|
|
460
476
|
"conflict": {
|
|
461
477
|
"title": {
|
|
462
478
|
"dependencies_unmet": "Заблоковано залежностями",
|
|
@@ -2569,6 +2585,23 @@
|
|
|
2569
2585
|
"review": "огляд",
|
|
2570
2586
|
"ralph": "Цикл Ralph"
|
|
2571
2587
|
},
|
|
2588
|
+
"reviewFriction": {
|
|
2589
|
+
"heading": "Тертя через борг рев’ю",
|
|
2590
|
+
"body": "Ускладнює створення нових завдань, поки завершена робота чекає на рев’ю людиною. Типово вимкнено. «Попереджати» додає підтвердження; «Примусово» повністю відмовляє у створенні після досягнення жорсткого ліміту.",
|
|
2591
|
+
"mode": "Режим",
|
|
2592
|
+
"modes": {
|
|
2593
|
+
"off": "Вимкнено",
|
|
2594
|
+
"warn": "Попереджати (підтвердити, щоб продовжити)",
|
|
2595
|
+
"enforce": "Примусово (жорстке блокування)"
|
|
2596
|
+
},
|
|
2597
|
+
"warnCount": "Попереджати від (завдань на рев’ю)",
|
|
2598
|
+
"enforceHint": "«Примусово» відмовляє у створенні завдань. Увімкніть принаймні один жорсткий тригер нижче.",
|
|
2599
|
+
"blockCountToggle": "Блокувати, коли забагато завдань на рев’ю",
|
|
2600
|
+
"blockCount": "Блокувати від (завдань на рев’ю)",
|
|
2601
|
+
"blockStuckToggle": "Блокувати, коли завдання чекає надто довго",
|
|
2602
|
+
"blockStuckMinutes": "Блокувати після (хвилин очікування)",
|
|
2603
|
+
"needsTrigger": "Режим «Примусово» потребує принаймні одного увімкненого жорсткого тригера (кількості або часу очікування)."
|
|
2604
|
+
},
|
|
2572
2605
|
"observability": {
|
|
2573
2606
|
"heading": "Спостережуваність агента",
|
|
2574
2607
|
"body": "Зберігайте повний контекст, наданий кожному агенту: складені промпти, вбудовані фрагменти найкращих практик і повний вміст файлів, впроваджених у його контейнер, щоб згодом їх можна було переглянути у вікні спостережуваності. Тіла зберігаються протягом того самого вікна, що й телеметрія LLM для кожного виклику. Вимкніть, щоб припинити зберігання (наявні знімки видаляються за політикою зберігання).",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cat-factory/app",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.151.1",
|
|
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",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"valibot": "^1.4.2",
|
|
41
41
|
"vue": "3.5.40",
|
|
42
42
|
"wretch": "^3.0.9",
|
|
43
|
-
"@cat-factory/contracts": "0.
|
|
43
|
+
"@cat-factory/contracts": "0.160.0"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@toad-contracts/testing": "0.3.2",
|