@cat-factory/app 0.224.0 → 0.225.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app/components/panels/AgentStepDetail.vue +63 -6
- package/app/components/pipeline/GateConfigFields.vue +187 -0
- package/app/components/pipeline/PipelineBuilder.vue +31 -0
- package/app/components/settings/ApiTokensPanel.vue +12 -4
- package/app/composables/useStepApproval.ts +74 -3
- package/app/stores/pipelines/draftActions.ts +2 -0
- package/app/stores/pipelines/draftGateConfig.ts +55 -0
- package/app/stores/pipelines/draftStepConfig.ts +2 -1
- package/app/stores/pipelines.ts +20 -1
- package/app/stores/publicApiKeys.spec.ts +1 -0
- package/app/stores/workspace/hydrate.ts +3 -0
- package/app/types/domain.ts +5 -0
- package/i18n/locales/de.json +18 -1
- package/i18n/locales/en.json +18 -1
- package/i18n/locales/es.json +18 -1
- package/i18n/locales/fr.json +18 -1
- package/i18n/locales/he.json +18 -1
- package/i18n/locales/it.json +18 -1
- package/i18n/locales/ja.json +18 -1
- package/i18n/locales/pl.json +18 -1
- package/i18n/locales/tr.json +18 -1
- package/i18n/locales/uk.json +18 -1
- package/package.json +2 -2
|
@@ -13,6 +13,7 @@ import BinaryOutputReport from '~/components/binaryOutput/BinaryOutputReport.vue
|
|
|
13
13
|
import EnvironmentStatusPanel from '~/components/environments/EnvironmentStatusPanel.vue'
|
|
14
14
|
import FrontendBindingsResolved from '~/components/panels/inspector/FrontendBindingsResolved.vue'
|
|
15
15
|
import { UI_TESTER_AGENT_KIND } from '@cat-factory/contracts'
|
|
16
|
+
import type { GateApprovalRefusal } from '@cat-factory/contracts'
|
|
16
17
|
import ProvisioningLogsDrawer from '~/components/provisioning/ProvisioningLogsDrawer.vue'
|
|
17
18
|
import IterationCapPrompt from '~/components/pipeline/IterationCapPrompt.vue'
|
|
18
19
|
import StepExecutionHistory from '~/components/board/StepExecutionHistory.vue'
|
|
@@ -227,6 +228,10 @@ const {
|
|
|
227
228
|
draftProposal,
|
|
228
229
|
rejectArmed,
|
|
229
230
|
canRequestChanges,
|
|
231
|
+
quorum: gateQuorum,
|
|
232
|
+
viewerHasApproved,
|
|
233
|
+
approvalWouldClearGate,
|
|
234
|
+
refusal: gateRefusal,
|
|
230
235
|
onProseClick,
|
|
231
236
|
addDraftComment,
|
|
232
237
|
cancelDraft,
|
|
@@ -241,6 +246,25 @@ const {
|
|
|
241
246
|
reject,
|
|
242
247
|
} = approval
|
|
243
248
|
|
|
249
|
+
/**
|
|
250
|
+
* Why the gate refuses this viewer, worded for them. An exhaustive Record over the shared refusal
|
|
251
|
+
* vocabulary with LITERAL keys, so the typed-message-key check sees them and a new refusal reason
|
|
252
|
+
* fails the typecheck instead of rendering as a blank line under a disabled button.
|
|
253
|
+
*/
|
|
254
|
+
const GATE_REFUSAL_KEYS: Record<GateApprovalRefusal, string> = {
|
|
255
|
+
not_a_gate_approver: 'panels.stepDetail.notAnApprover',
|
|
256
|
+
gate_approver_identity_required: 'panels.stepDetail.approverIdentityRequired',
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Whether "approve with corrections" is offered RIGHT NOW. Two independent reasons withhold it,
|
|
261
|
+
* and they are kept apart because their remedies differ: an output that is a rendering can never
|
|
262
|
+
* be edited here, while an unmet quorum only means not yet: this viewer's approval is not the
|
|
263
|
+
* one that clears the gate, and an edit under it would move the artifact beneath the approvals
|
|
264
|
+
* already recorded. Each states itself below rather than the button quietly vanishing.
|
|
265
|
+
*/
|
|
266
|
+
const proposalEditableNow = computed(() => proposalEditable.value && approvalWouldClearGate.value)
|
|
267
|
+
|
|
244
268
|
const resolvingCap = ref(false)
|
|
245
269
|
async function resolveCompanionCap(choice: IterationCapChoice) {
|
|
246
270
|
if (!ctx.value || !approvalId.value || resolvingCap.value) return
|
|
@@ -692,6 +716,30 @@ async function copyOutput() {
|
|
|
692
716
|
<p class="mt-1 text-[12px] text-slate-400">
|
|
693
717
|
{{ editing ? t('panels.stepDetail.editHint') : t('panels.stepDetail.reviewHint') }}
|
|
694
718
|
</p>
|
|
719
|
+
<!-- The gate's configured POLICY, when it has one. Both lines exist because an
|
|
720
|
+
approve on such a gate legitimately may not advance the run: without the tally, a
|
|
721
|
+
correctly-recorded approval is indistinguishable from a call that failed, and
|
|
722
|
+
without the refusal a person would press a button the server answers 403. -->
|
|
723
|
+
<p
|
|
724
|
+
v-if="gateQuorum"
|
|
725
|
+
class="mt-1 text-[12px] text-amber-300/90"
|
|
726
|
+
data-testid="gate-quorum"
|
|
727
|
+
>
|
|
728
|
+
{{
|
|
729
|
+
t('panels.stepDetail.quorumProgress', {
|
|
730
|
+
recorded: gateQuorum.recorded,
|
|
731
|
+
required: gateQuorum.required,
|
|
732
|
+
})
|
|
733
|
+
}}
|
|
734
|
+
<span v-if="viewerHasApproved">{{ t('panels.stepDetail.quorumYours') }}</span>
|
|
735
|
+
</p>
|
|
736
|
+
<p
|
|
737
|
+
v-if="gateRefusal"
|
|
738
|
+
class="mt-1 text-[12px] text-slate-400"
|
|
739
|
+
data-testid="gate-not-approver"
|
|
740
|
+
>
|
|
741
|
+
{{ t(GATE_REFUSAL_KEYS[gateRefusal]) }}
|
|
742
|
+
</p>
|
|
695
743
|
</div>
|
|
696
744
|
|
|
697
745
|
<div class="flex-1 space-y-3 overflow-auto overscroll-contain px-4 py-3">
|
|
@@ -820,27 +868,36 @@ async function copyOutput() {
|
|
|
820
868
|
size="sm"
|
|
821
869
|
icon="i-lucide-check"
|
|
822
870
|
block
|
|
823
|
-
:disabled="rejectArmed"
|
|
871
|
+
:disabled="rejectArmed || !!gateRefusal"
|
|
824
872
|
:loading="submitting"
|
|
825
873
|
@click="approve"
|
|
826
874
|
>
|
|
827
875
|
{{ t('panels.stepDetail.approveAndProceed') }}
|
|
828
876
|
</UButton>
|
|
829
877
|
<UButton
|
|
830
|
-
v-if="
|
|
878
|
+
v-if="proposalEditableNow"
|
|
831
879
|
color="primary"
|
|
832
880
|
variant="soft"
|
|
833
881
|
size="sm"
|
|
834
882
|
icon="i-lucide-pencil"
|
|
835
883
|
block
|
|
836
|
-
:disabled="rejectArmed || submitting"
|
|
884
|
+
:disabled="rejectArmed || submitting || !!gateRefusal"
|
|
837
885
|
@click="startEditing"
|
|
838
886
|
>
|
|
839
887
|
{{ t('panels.stepDetail.approveWithCorrections') }}
|
|
840
888
|
</UButton>
|
|
841
|
-
<p
|
|
889
|
+
<p
|
|
890
|
+
v-else-if="!proposalEditable"
|
|
891
|
+
class="text-[10px] text-slate-500"
|
|
892
|
+
data-testid="step-rendered-output-note"
|
|
893
|
+
>
|
|
842
894
|
{{ t('panels.stepDetail.renderedOutputNote') }}
|
|
843
895
|
</p>
|
|
896
|
+
<!-- Withheld only until the quorum is one approval away, so it says so rather than
|
|
897
|
+
leaving a reviewer to wonder where the affordance went. -->
|
|
898
|
+
<p v-else class="text-[10px] text-slate-500" data-testid="step-quorum-edit-locked">
|
|
899
|
+
{{ t('panels.stepDetail.quorumEditLocked') }}
|
|
900
|
+
</p>
|
|
844
901
|
|
|
845
902
|
<!-- destructive: a two-step inline confirm instead of a native dialog -->
|
|
846
903
|
<div
|
|
@@ -881,7 +938,7 @@ async function copyOutput() {
|
|
|
881
938
|
icon="i-lucide-rotate-ccw"
|
|
882
939
|
class="flex-1"
|
|
883
940
|
data-testid="step-request-changes"
|
|
884
|
-
:disabled="!canRequestChanges"
|
|
941
|
+
:disabled="!canRequestChanges || !!gateRefusal"
|
|
885
942
|
:loading="submitting"
|
|
886
943
|
@click="requestChanges"
|
|
887
944
|
>
|
|
@@ -893,7 +950,7 @@ async function copyOutput() {
|
|
|
893
950
|
size="sm"
|
|
894
951
|
icon="i-lucide-ban"
|
|
895
952
|
class="flex-1"
|
|
896
|
-
:disabled="submitting"
|
|
953
|
+
:disabled="submitting || !!gateRefusal"
|
|
897
954
|
@click="armReject"
|
|
898
955
|
>
|
|
899
956
|
{{ t('panels.stepDetail.reject') }}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
// One step's GATE configuration in the pipeline builder: who may clear its human approval gate,
|
|
3
|
+
// how many of them must, and the parameters of the registered gate the step's kind runs.
|
|
4
|
+
//
|
|
5
|
+
// Two halves with deliberately different sources, rendered together because they are one question
|
|
6
|
+
// to the author ("how does this checkpoint behave?"):
|
|
7
|
+
//
|
|
8
|
+
// - the approval policy is PLATFORM-typed (`StepGateConfig.approvers` / `minApprovals`), so it
|
|
9
|
+
// gets purpose-built controls and the shared rules from `@cat-factory/contracts` decide what
|
|
10
|
+
// counts as configured;
|
|
11
|
+
// - the gate's own parameters are DECLARED BY THE GATE (`gateConfigForms` on the snapshot) and
|
|
12
|
+
// rendered through the shared `DescriptorFields`, so a deployment's gate gets an authoring
|
|
13
|
+
// form from its registration alone and this component learns nothing about it.
|
|
14
|
+
//
|
|
15
|
+
// Extracted rather than inlined into `PipelineBuilder.vue` for the size rule (split along a seam,
|
|
16
|
+
// never grow the ratchet) and because the approver controls need a roster load this component can
|
|
17
|
+
// own on its own terms.
|
|
18
|
+
import { computed, ref, watch } from 'vue'
|
|
19
|
+
import { MAX_GATE_APPROVALS, requiredGateApprovals } from '@cat-factory/contracts'
|
|
20
|
+
import type { DescriptorFieldValues, StepGateConfig, WorkspaceRole } from '~/types/domain'
|
|
21
|
+
import DescriptorFields from '~/components/common/DescriptorFields.vue'
|
|
22
|
+
|
|
23
|
+
const props = defineProps<{
|
|
24
|
+
/** The step's index in the draft, for the store patch. */
|
|
25
|
+
index: number
|
|
26
|
+
/** Whether the step carries a human approval gate (the approval half renders only then). */
|
|
27
|
+
gated: boolean
|
|
28
|
+
/** The step's agent kind, for looking up its registered gate's declared parameters. */
|
|
29
|
+
kind: string
|
|
30
|
+
}>()
|
|
31
|
+
|
|
32
|
+
const { t } = useI18n()
|
|
33
|
+
const pipelines = usePipelinesStore()
|
|
34
|
+
const workspace = useWorkspaceStore()
|
|
35
|
+
const members = useWorkspaceMembersStore()
|
|
36
|
+
|
|
37
|
+
const config = computed<StepGateConfig>(() => pipelines.draftGateConfig(props.index) ?? {})
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* The roles a gate may name. `viewer` is deliberately absent: the workspace RBAC write floor
|
|
41
|
+
* refuses a viewer's resolution before the policy is ever consulted, so offering it would let an
|
|
42
|
+
* author configure an approver who can never approve.
|
|
43
|
+
*/
|
|
44
|
+
const APPROVER_ROLES: readonly WorkspaceRole[] = ['admin', 'member']
|
|
45
|
+
|
|
46
|
+
const ROLE_LABEL_KEYS: Record<'admin' | 'member', string> = {
|
|
47
|
+
admin: 'pipeline.gateConfig.roleAdmin',
|
|
48
|
+
member: 'pipeline.gateConfig.roleMember',
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const requiredApprovals = computed(() => requiredGateApprovals(config.value))
|
|
52
|
+
|
|
53
|
+
// The roster backs the named-approver picker. Loaded lazily the first time this panel renders (it
|
|
54
|
+
// is not on the board snapshot) and only when the caller has a workspace — every resolved role may
|
|
55
|
+
// read it, so this is not an admin-only affordance.
|
|
56
|
+
const rosterLoaded = ref(false)
|
|
57
|
+
watch(
|
|
58
|
+
() => [props.gated, workspace.workspaceId] as const,
|
|
59
|
+
async ([gated, workspaceId]) => {
|
|
60
|
+
if (!gated || !workspaceId || rosterLoaded.value) return
|
|
61
|
+
rosterLoaded.value = true
|
|
62
|
+
await members.load(workspaceId)
|
|
63
|
+
},
|
|
64
|
+
{ immediate: true },
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
const memberOptions = computed(() =>
|
|
68
|
+
members.members.map((m) => ({ value: m.userId, label: m.name || m.email || m.userId })),
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
function toggleRole(role: WorkspaceRole, on: boolean) {
|
|
72
|
+
const roles = new Set<WorkspaceRole>(config.value.approvers?.roles ?? [])
|
|
73
|
+
if (on) roles.add(role)
|
|
74
|
+
else roles.delete(role)
|
|
75
|
+
patchApprovers({ roles: [...roles] })
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function setNamedApprovers(userIds: string[]) {
|
|
79
|
+
patchApprovers({ userIds })
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Write one axis of the approver policy back, keeping the other. Empty arrays are dropped rather
|
|
84
|
+
* than stored: `{ roles: [] }` names nobody, and a policy that names nobody would refuse every
|
|
85
|
+
* approver and park the run forever — so "no rule" has to persist as an ABSENT rule.
|
|
86
|
+
*/
|
|
87
|
+
function patchApprovers(patch: { roles?: WorkspaceRole[]; userIds?: string[] }) {
|
|
88
|
+
const merged = { ...config.value.approvers, ...patch }
|
|
89
|
+
const approvers: NonNullable<StepGateConfig['approvers']> = {}
|
|
90
|
+
if (merged.roles?.length) approvers.roles = merged.roles
|
|
91
|
+
if (merged.userIds?.length) approvers.userIds = merged.userIds
|
|
92
|
+
pipelines.patchDraftGateConfig(props.index, {
|
|
93
|
+
approvers: Object.keys(approvers).length ? approvers : undefined,
|
|
94
|
+
})
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function setRequiredApprovals(raw: string) {
|
|
98
|
+
const parsed = Number.parseInt(raw, 10)
|
|
99
|
+
const bounded = Number.isFinite(parsed) ? Math.min(Math.max(parsed, 1), MAX_GATE_APPROVALS) : 1
|
|
100
|
+
// The store drops a value of 1 (the default), so an author who types the default back persists
|
|
101
|
+
// nothing — the same normalization every other per-step option follows.
|
|
102
|
+
pipelines.patchDraftGateConfig(props.index, { minApprovals: bounded })
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** The parameters the registered gate for this step's kind declares, if any. */
|
|
106
|
+
const gateFields = computed(
|
|
107
|
+
() => pipelines.gateConfigForms.find((form) => form.kind === props.kind)?.fields,
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
const gateFieldValues = computed<DescriptorFieldValues>({
|
|
111
|
+
get: () => config.value.fields ?? {},
|
|
112
|
+
set: (fields) => pipelines.patchDraftGateConfig(props.index, { fields }),
|
|
113
|
+
})
|
|
114
|
+
</script>
|
|
115
|
+
|
|
116
|
+
<template>
|
|
117
|
+
<div v-if="gated || gateFields?.length" class="ms-6 space-y-2" data-testid="gate-config">
|
|
118
|
+
<div v-if="gated" class="space-y-2 rounded-md border border-amber-800/40 bg-amber-950/10 p-2">
|
|
119
|
+
<div class="flex flex-wrap items-center gap-2 text-[10px]">
|
|
120
|
+
<span class="text-slate-500">{{ t('pipeline.gateConfig.approversLabel') }}</span>
|
|
121
|
+
<label
|
|
122
|
+
v-for="role in APPROVER_ROLES"
|
|
123
|
+
:key="role"
|
|
124
|
+
class="flex items-center gap-1 text-slate-400"
|
|
125
|
+
>
|
|
126
|
+
<input
|
|
127
|
+
type="checkbox"
|
|
128
|
+
:checked="config.approvers?.roles?.includes(role) ?? false"
|
|
129
|
+
:data-testid="`gate-approver-role-${role}`"
|
|
130
|
+
@change="toggleRole(role, ($event.target as HTMLInputElement).checked)"
|
|
131
|
+
/>
|
|
132
|
+
{{ t(ROLE_LABEL_KEYS[role as 'admin' | 'member']) }}
|
|
133
|
+
</label>
|
|
134
|
+
</div>
|
|
135
|
+
|
|
136
|
+
<div class="flex flex-wrap items-center gap-2 text-[10px]">
|
|
137
|
+
<span class="text-slate-500">{{ t('pipeline.gateConfig.namedApproversLabel') }}</span>
|
|
138
|
+
<USelectMenu
|
|
139
|
+
class="w-64"
|
|
140
|
+
multiple
|
|
141
|
+
size="xs"
|
|
142
|
+
value-key="value"
|
|
143
|
+
:items="memberOptions"
|
|
144
|
+
:model-value="config.approvers?.userIds ?? []"
|
|
145
|
+
:placeholder="t('pipeline.gateConfig.namedApproversPlaceholder')"
|
|
146
|
+
data-testid="gate-named-approvers"
|
|
147
|
+
@update:model-value="setNamedApprovers(($event ?? []) as string[])"
|
|
148
|
+
/>
|
|
149
|
+
</div>
|
|
150
|
+
|
|
151
|
+
<div class="flex flex-wrap items-center gap-2 text-[10px]">
|
|
152
|
+
<label class="text-slate-500" :title="t('pipeline.gateConfig.requiredApprovalsHint')">
|
|
153
|
+
{{ t('pipeline.gateConfig.requiredApprovalsLabel') }}
|
|
154
|
+
</label>
|
|
155
|
+
<input
|
|
156
|
+
:value="requiredApprovals"
|
|
157
|
+
type="number"
|
|
158
|
+
min="1"
|
|
159
|
+
:max="MAX_GATE_APPROVALS"
|
|
160
|
+
step="1"
|
|
161
|
+
class="w-14 rounded border border-slate-700 bg-slate-900 px-1.5 py-0.5 text-slate-100"
|
|
162
|
+
data-testid="gate-required-approvals"
|
|
163
|
+
@change="setRequiredApprovals(($event.target as HTMLInputElement).value)"
|
|
164
|
+
/>
|
|
165
|
+
<span class="text-slate-500">{{ t('pipeline.gateConfig.requiredApprovalsHint') }}</span>
|
|
166
|
+
</div>
|
|
167
|
+
|
|
168
|
+
<p v-if="!config.approvers" class="text-[10px] text-slate-500">
|
|
169
|
+
{{ t('pipeline.gateConfig.anyoneHint') }}
|
|
170
|
+
</p>
|
|
171
|
+
</div>
|
|
172
|
+
|
|
173
|
+
<!-- The registered gate's OWN parameters, rendered from what it declared. Labels and help are
|
|
174
|
+
the gate's own English (the descriptor-form convention); only the heading is i18n. -->
|
|
175
|
+
<div
|
|
176
|
+
v-if="gateFields?.length"
|
|
177
|
+
class="space-y-2 rounded-md border border-slate-800 bg-slate-900/40 p-2"
|
|
178
|
+
>
|
|
179
|
+
<p class="text-[10px] text-slate-500">{{ t('pipeline.gateConfig.gateParametersLabel') }}</p>
|
|
180
|
+
<DescriptorFields
|
|
181
|
+
v-model="gateFieldValues"
|
|
182
|
+
:fields="gateFields"
|
|
183
|
+
testid-prefix="gate-parameter"
|
|
184
|
+
/>
|
|
185
|
+
</div>
|
|
186
|
+
</div>
|
|
187
|
+
</template>
|
|
@@ -6,6 +6,7 @@ import AgentPalette from '~/components/palettes/AgentPalette.vue'
|
|
|
6
6
|
import AgentKindIcon from '~/components/pipeline/AgentKindIcon.vue'
|
|
7
7
|
import AgentPromptEditor from '~/components/pipeline/AgentPromptEditor.vue'
|
|
8
8
|
import EstimateThresholdFields from '~/components/pipeline/EstimateThresholdFields.vue'
|
|
9
|
+
import GateConfigFields from '~/components/pipeline/GateConfigFields.vue'
|
|
9
10
|
import OutputBudgetInput from '~/components/pipeline/OutputBudgetInput.vue'
|
|
10
11
|
import BinaryOutputStepPicker from '~/components/pipeline/BinaryOutputStepPicker.vue'
|
|
11
12
|
import { ESTIMATE_AXES, ESTIMATE_AXIS_FIELD, type EstimateAxis } from '~/utils/estimateGating'
|
|
@@ -164,6 +165,23 @@ function showVariantPicker(index: number, kind: AgentKind): boolean {
|
|
|
164
165
|
return showOverrideField(uiMode.isAdvanced, pipelines.draftAgentVariantId(index) ?? null)
|
|
165
166
|
}
|
|
166
167
|
|
|
168
|
+
/**
|
|
169
|
+
* Whether to offer this step's GATE configuration (approvers + required approvals, and any
|
|
170
|
+
* parameters its registered gate declares). There has to be something to configure: either the
|
|
171
|
+
* step carries a human approval gate, or its kind has a registered gate that declares parameters.
|
|
172
|
+
*
|
|
173
|
+
* Then it is an OVERRIDE like the variant picker above — advanced-only until a value is actually
|
|
174
|
+
* set, and visible in both tiers from then on. That second half is load-bearing here rather than
|
|
175
|
+
* cosmetic: the builder saves the whole step-options bag, so a configured policy invisible to a
|
|
176
|
+
* basic-mode editor would be a policy they silently save over.
|
|
177
|
+
*/
|
|
178
|
+
function showGateConfig(index: number, kind: AgentKind): boolean {
|
|
179
|
+
const gated = pipelines.draftGates[index] === true
|
|
180
|
+
const declaresFields = pipelines.gateConfigForms.some((form) => form.kind === kind)
|
|
181
|
+
if (!gated && !declaresFields) return false
|
|
182
|
+
return showOverrideField(uiMode.isAdvanced, pipelines.draftGateConfig(index) ?? null)
|
|
183
|
+
}
|
|
184
|
+
|
|
167
185
|
/**
|
|
168
186
|
* The variants registered for a step's kind as USelect items, with an explicit "shipped prompt"
|
|
169
187
|
* entry so clearing the pick is a choice in the same list rather than a separate affordance.
|
|
@@ -843,6 +861,19 @@ async function clone(p: Pipeline) {
|
|
|
843
861
|
/>
|
|
844
862
|
</div>
|
|
845
863
|
|
|
864
|
+
<!-- Gate configuration: who may clear this step's approval gate and how many of
|
|
865
|
+
them, plus the parameters its registered gate declares. An OVERRIDE of the
|
|
866
|
+
defaults (one approval from anyone entitled to write, the gate's shipped knobs),
|
|
867
|
+
so it is advanced-only until a step actually configures something — at which point
|
|
868
|
+
it must stay visible in both tiers, or a member editing the pipeline would save
|
|
869
|
+
over a policy they were never shown. -->
|
|
870
|
+
<GateConfigFields
|
|
871
|
+
v-if="showGateConfig(unit.index, unit.kind)"
|
|
872
|
+
:index="unit.index"
|
|
873
|
+
:gated="pipelines.draftGates[unit.index] === true"
|
|
874
|
+
:kind="unit.kind"
|
|
875
|
+
/>
|
|
876
|
+
|
|
846
877
|
<!-- Binary-output picker: a generator kind's step is parametrized by the
|
|
847
878
|
foundational STORAGE service its artifacts go through (`stepOptions.binaryOutput`)
|
|
848
879
|
plus any services consulted for the generation's scope. Required, not an
|
|
@@ -38,12 +38,20 @@ const auth = useAuthStore()
|
|
|
38
38
|
const store = usePublicApiKeysStore()
|
|
39
39
|
|
|
40
40
|
/**
|
|
41
|
-
* The minter to attribute a key to.
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
41
|
+
* The minter to attribute a key to. When the minter is the signed-in user we show a localized
|
|
42
|
+
* "you"; for another person, the raw `usr_*` id (the list has no user-name lookup, so the audit id
|
|
43
|
+
* is the honest, non-misleading thing to show).
|
|
44
|
+
*
|
|
45
|
+
* A key PROVISIONED HEADLESSLY (`POST /api/v1/keys`) has no user and names the KEY that minted
|
|
46
|
+
* it instead. Reading `createdByKeyId` here is not a nicety: a headless mint stores a null user,
|
|
47
|
+
* so without this branch it would render exactly like a key that predates the audit column, and
|
|
48
|
+
* "nobody knows who made this" would be shown for the one case the platform knows precisely.
|
|
49
|
+
* `null` stays reserved for genuinely unattributed keys, where the row omits the segment.
|
|
45
50
|
*/
|
|
46
51
|
function minterLabel(key: PublicApiKey): string | null {
|
|
52
|
+
if (key.createdByKeyId) {
|
|
53
|
+
return t('settings.apiTokens.list.createdByKey', { id: key.createdByKeyId })
|
|
54
|
+
}
|
|
47
55
|
if (!key.createdByUserId) return null
|
|
48
56
|
return key.createdByUserId === auth.user?.id
|
|
49
57
|
? t('settings.apiTokens.list.createdByYou')
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { ref, computed, nextTick } from 'vue'
|
|
2
|
+
import { refuseGateResolution, UNATTRIBUTED_GATE_ACTOR } from '@cat-factory/contracts'
|
|
3
|
+
import type { GateActor, GateApprovalRefusal } from '@cat-factory/contracts'
|
|
2
4
|
import type { PipelineStep } from '~/types/execution'
|
|
3
5
|
import { useProseComments } from '~/composables/useProseComments'
|
|
6
|
+
import { useWorkspaceAccess } from '~/composables/useWorkspaceAccess'
|
|
4
7
|
|
|
5
8
|
/**
|
|
6
9
|
* The GitHub-style approval/review state machine for a pending gate step. When the
|
|
@@ -23,6 +26,8 @@ export function useStepApproval(opts: {
|
|
|
23
26
|
close: () => void
|
|
24
27
|
}) {
|
|
25
28
|
const execution = useExecutionStore()
|
|
29
|
+
const auth = useAuthStore()
|
|
30
|
+
const access = useWorkspaceAccess()
|
|
26
31
|
|
|
27
32
|
const feedback = ref('')
|
|
28
33
|
const submitting = ref(false)
|
|
@@ -60,12 +65,71 @@ export function useStepApproval(opts: {
|
|
|
60
65
|
() => !!feedback.value.trim() || reviewComments.value.length > 0,
|
|
61
66
|
)
|
|
62
67
|
|
|
68
|
+
// ---- The gate's own POLICY, as the pipeline step configured it -------------------------
|
|
69
|
+
//
|
|
70
|
+
// Read from the SAME `@cat-factory/contracts` rules the engine enforces, never a local
|
|
71
|
+
// reimplementation: a button enabled by a second copy of the rule is a request the server
|
|
72
|
+
// refuses, and the person pressing it has no way to tell which of the two is right.
|
|
73
|
+
|
|
74
|
+
const approval = computed(() => opts.step()?.approval ?? null)
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* The gate's quorum, or null when it needs the usual single approval. Non-null is what makes
|
|
78
|
+
* the rail say "1 of 2 approvals" — otherwise an approve that correctly leaves the run parked
|
|
79
|
+
* looks exactly like one that failed.
|
|
80
|
+
*/
|
|
81
|
+
const quorum = computed(() => {
|
|
82
|
+
const required = approval.value?.requiredApprovals ?? 1
|
|
83
|
+
if (required <= 1) return null
|
|
84
|
+
return { required, recorded: approval.value?.approvals?.length ?? 0 }
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
/** Whether the viewer's own approval is already counted (so the rail can say so). */
|
|
88
|
+
const viewerHasApproved = computed(() => {
|
|
89
|
+
const userId = auth.user?.id
|
|
90
|
+
return !!userId && !!approval.value?.approvals?.some((a) => a.actorId === userId)
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Whether the viewer's approval would be the one that CLEARS the gate. Always true without a
|
|
95
|
+
* quorum; under one it folds the viewer in the way the server does, so a re-approval by someone
|
|
96
|
+
* already counted does not read as a new vote.
|
|
97
|
+
*
|
|
98
|
+
* This is what decides whether "approve with corrections" is offered: a quorum votes on ONE
|
|
99
|
+
* artifact, so an edit that does not clear the gate would rewrite the proposal under the people
|
|
100
|
+
* already counted toward it and the ones still to come. The server refuses that
|
|
101
|
+
* (`proposal_not_editable_until_quorum`); hiding the affordance is what stops a reviewer typing
|
|
102
|
+
* a correction into a dead end, the same disposition as `outputIsRendered`.
|
|
103
|
+
*/
|
|
104
|
+
const approvalWouldClearGate = computed(() => {
|
|
105
|
+
const q = quorum.value
|
|
106
|
+
if (!q) return true
|
|
107
|
+
return (viewerHasApproved.value ? q.recorded : q.recorded + 1) >= q.required
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Why the viewer may not resolve this gate, or null when they may. Drives the disabled state of
|
|
112
|
+
* all three verbs, since the policy governs every resolution and not just approve.
|
|
113
|
+
*
|
|
114
|
+
* With auth off there is no signed-in user, and the actor is `unattributed` — exactly what the
|
|
115
|
+
* server will decide with, so the rail refuses ahead of it rather than offering a button whose
|
|
116
|
+
* request comes back 403.
|
|
117
|
+
*/
|
|
118
|
+
const refusal = computed<GateApprovalRefusal | null>(() => {
|
|
119
|
+
if (!approval.value) return null
|
|
120
|
+
const user = auth.user
|
|
121
|
+
const actor: GateActor = user
|
|
122
|
+
? { id: user.id, kind: 'user', role: access.role.value }
|
|
123
|
+
: { id: UNATTRIBUTED_GATE_ACTOR, kind: 'unattributed', role: access.role.value }
|
|
124
|
+
return refuseGateResolution(approval.value.approverPolicy, actor)
|
|
125
|
+
})
|
|
126
|
+
|
|
63
127
|
// Plain approve: accept the agent's proposal verbatim and advance. Every action below
|
|
64
128
|
// closes the overlay ONLY when the command actually ran — a server refusal (surfaced as
|
|
65
129
|
// a toast by the store) or a cancelled credential prompt keeps the review open.
|
|
66
130
|
async function approve() {
|
|
67
131
|
const id = opts.approvalId()
|
|
68
|
-
if (!opts.instanceId() || !id || submitting.value) return
|
|
132
|
+
if (!opts.instanceId() || !id || submitting.value || refusal.value) return
|
|
69
133
|
submitting.value = true
|
|
70
134
|
try {
|
|
71
135
|
if (await execution.approveStep(opts.instanceId()!, id)) opts.close()
|
|
@@ -88,7 +152,9 @@ export function useStepApproval(opts: {
|
|
|
88
152
|
}
|
|
89
153
|
async function approveWithEdits() {
|
|
90
154
|
const id = opts.approvalId()
|
|
91
|
-
if (!opts.instanceId() || !id || submitting.value) return
|
|
155
|
+
if (!opts.instanceId() || !id || submitting.value || refusal.value) return
|
|
156
|
+
// The server refuses an edit that does not clear the gate; never send one.
|
|
157
|
+
if (!approvalWouldClearGate.value) return
|
|
92
158
|
submitting.value = true
|
|
93
159
|
try {
|
|
94
160
|
if (await execution.approveStep(opts.instanceId()!, id, draftProposal.value)) opts.close()
|
|
@@ -99,6 +165,7 @@ export function useStepApproval(opts: {
|
|
|
99
165
|
async function requestChanges() {
|
|
100
166
|
const id = opts.approvalId()
|
|
101
167
|
if (!opts.instanceId() || !id || submitting.value || !canRequestChanges.value) return
|
|
168
|
+
if (refusal.value) return
|
|
102
169
|
submitting.value = true
|
|
103
170
|
try {
|
|
104
171
|
const ok = await execution.requestStepChanges(opts.instanceId()!, id, {
|
|
@@ -118,7 +185,7 @@ export function useStepApproval(opts: {
|
|
|
118
185
|
}
|
|
119
186
|
async function reject() {
|
|
120
187
|
const id = opts.approvalId()
|
|
121
|
-
if (!opts.instanceId() || !id || submitting.value) return
|
|
188
|
+
if (!opts.instanceId() || !id || submitting.value || refusal.value) return
|
|
122
189
|
submitting.value = true
|
|
123
190
|
try {
|
|
124
191
|
if (await execution.rejectStep(opts.instanceId()!, id, feedback.value.trim() || undefined)) {
|
|
@@ -159,6 +226,10 @@ export function useStepApproval(opts: {
|
|
|
159
226
|
draftProposal,
|
|
160
227
|
rejectArmed,
|
|
161
228
|
canRequestChanges,
|
|
229
|
+
quorum,
|
|
230
|
+
viewerHasApproved,
|
|
231
|
+
approvalWouldClearGate,
|
|
232
|
+
refusal,
|
|
162
233
|
syncHighlights,
|
|
163
234
|
onProseClick,
|
|
164
235
|
addDraftComment,
|
|
@@ -2,6 +2,7 @@ import { computed } from 'vue'
|
|
|
2
2
|
import type { AgentKind, Pipeline } from '~/types/domain'
|
|
3
3
|
import { companionForProducer } from '~/utils/catalog'
|
|
4
4
|
import type { PipelinesContext } from './context'
|
|
5
|
+
import { createPipelineGateConfigActions } from './draftGateConfig'
|
|
5
6
|
import { createPipelineStepConfigActions } from './draftStepConfig'
|
|
6
7
|
|
|
7
8
|
/**
|
|
@@ -192,6 +193,7 @@ export function createPipelineDraftActions(ctx: PipelinesContext) {
|
|
|
192
193
|
|
|
193
194
|
return {
|
|
194
195
|
...createPipelineStepConfigActions(ctx),
|
|
196
|
+
...createPipelineGateConfigActions(ctx),
|
|
195
197
|
addToDraft,
|
|
196
198
|
removeFromDraft,
|
|
197
199
|
moveInDraft,
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { StepGateConfig, StepOptions } from '@cat-factory/contracts'
|
|
2
|
+
import { hasApproverPolicy } from '@cat-factory/contracts'
|
|
3
|
+
import type { PipelinesContext } from './context'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The pipeline-builder draft's per-step GATE configuration: who may clear a step's human approval
|
|
7
|
+
* gate, how many of them must, and the parameters the step's registered gate declares.
|
|
8
|
+
*
|
|
9
|
+
* Its own module rather than another pair of accessors on `./draftStepConfig`, which owns the flat
|
|
10
|
+
* per-step options (a skill id, a variant id, a token ceiling — each one field, read and written
|
|
11
|
+
* whole). Gate config is the one nested value there: it MERGES a patch across two independently
|
|
12
|
+
* edited halves and normalizes at three levels on the way out, which is a different enough shape to
|
|
13
|
+
* be worth reading on its own. (It also put that file over the per-function line budget, which is
|
|
14
|
+
* the ratchet doing its job rather than a number to raise.)
|
|
15
|
+
*/
|
|
16
|
+
export function createPipelineGateConfigActions(ctx: PipelinesContext) {
|
|
17
|
+
const { draftStepOptions } = ctx
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The gate configuration on the draft step at `index`, or undefined when the step takes every
|
|
21
|
+
* default (one approval from anyone entitled to write, and the gate's shipped knobs).
|
|
22
|
+
*/
|
|
23
|
+
function draftGateConfig(index: number): StepGateConfig | undefined {
|
|
24
|
+
return draftStepOptions.value[index]?.gateConfig
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Merge a PATCH into the draft step's gate configuration. A patch rather than a whole-value set
|
|
29
|
+
* because the builder edits the two halves through different controls: a whole-value write from
|
|
30
|
+
* the approver fields would drop the gate's own parameters, and vice versa.
|
|
31
|
+
*
|
|
32
|
+
* Normalizes downward at every level: a field set back to its default is deleted, an emptied
|
|
33
|
+
* `gateConfig` is dropped, and an emptied options bag becomes `null`. So a step returned to the
|
|
34
|
+
* defaults persists nothing at all — the same rule the other per-step options follow, and what
|
|
35
|
+
* keeps an all-default pipeline from growing a `step_options` array it does not need.
|
|
36
|
+
*
|
|
37
|
+
* An empty approver policy is dropped rather than stored, and that one is not just tidiness:
|
|
38
|
+
* `{ roles: [] }` names nobody, and a policy naming nobody would refuse every approver and park
|
|
39
|
+
* the run forever. "No rule" has to persist as an ABSENT rule.
|
|
40
|
+
*/
|
|
41
|
+
function patchDraftGateConfig(index: number, patch: Partial<StepGateConfig>) {
|
|
42
|
+
const gateConfig: StepGateConfig = { ...draftGateConfig(index), ...patch }
|
|
43
|
+
if (!hasApproverPolicy(gateConfig.approvers)) delete gateConfig.approvers
|
|
44
|
+
if (gateConfig.minApprovals !== undefined && gateConfig.minApprovals <= 1) {
|
|
45
|
+
delete gateConfig.minApprovals
|
|
46
|
+
}
|
|
47
|
+
if (gateConfig.fields && Object.keys(gateConfig.fields).length === 0) delete gateConfig.fields
|
|
48
|
+
const next: StepOptions = { ...draftStepOptions.value[index] }
|
|
49
|
+
if (Object.keys(gateConfig).length) next.gateConfig = gateConfig
|
|
50
|
+
else delete next.gateConfig
|
|
51
|
+
draftStepOptions.value[index] = Object.keys(next).length ? next : null
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return { draftGateConfig, patchDraftGateConfig }
|
|
55
|
+
}
|
|
@@ -7,7 +7,8 @@ import { defaultConsensusConfig, type PipelinesContext } from './context'
|
|
|
7
7
|
* consensus-GROUP tier set), the human approval gate, the estimate gate on a companion step, the
|
|
8
8
|
* follow-up and test-QC companions, the per-step enable flag, and the `StepOptions` bag
|
|
9
9
|
* (requirements auto-recommendation, the picked skill, the picked agent-kind variant, the
|
|
10
|
-
* per-step output-token ceiling, the binary-output storage/context selection).
|
|
10
|
+
* per-step output-token ceiling, the binary-output storage/context selection). The step's GATE
|
|
11
|
+
* configuration is the sibling `./draftGateConfig`, which explains why it is not here.
|
|
11
12
|
*
|
|
12
13
|
* Split out of `./draftActions`, which owns the draft's STRUCTURE (insert / remove / reorder /
|
|
13
14
|
* units). Every function here reads and writes one of the parallel per-step arrays at an index and
|
package/app/stores/pipelines.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { defineStore } from 'pinia'
|
|
2
2
|
import { ref } from 'vue'
|
|
3
3
|
import type { Pipeline } from '~/types/domain'
|
|
4
|
-
import type { PipelinePurpose, RetiredPipelineWire } from '@cat-factory/contracts'
|
|
4
|
+
import type { GateConfigForm, PipelinePurpose, RetiredPipelineWire } from '@cat-factory/contracts'
|
|
5
5
|
import { useUpsertList } from '~/composables/useUpsertList'
|
|
6
6
|
import { createDraftStepState, type PipelinesContext } from '~/stores/pipelines/context'
|
|
7
7
|
import { createPipelineDraftActions } from '~/stores/pipelines/draftActions'
|
|
@@ -39,6 +39,13 @@ export const usePipelinesStore = defineStore('pipelines', () => {
|
|
|
39
39
|
* `usePipelineHealth`). Disjoint from {@link catalogVersions} by construction.
|
|
40
40
|
*/
|
|
41
41
|
const retiredPipelines = ref<RetiredPipelineWire[]>([])
|
|
42
|
+
/**
|
|
43
|
+
* The per-step parameters each registered GATE declares, projected from the deployment's gate
|
|
44
|
+
* registry onto the board snapshot. The builder renders a gated step's own config form from
|
|
45
|
+
* these, so what it can save is exactly what run admission validates. Empty on a deployment
|
|
46
|
+
* whose gates declare nothing.
|
|
47
|
+
*/
|
|
48
|
+
const gateConfigForms = ref<GateConfigForm[]>([])
|
|
42
49
|
|
|
43
50
|
// The per-step, index-aligned draft arrays (kept in lockstep — see `createDraftStepState`).
|
|
44
51
|
const {
|
|
@@ -83,6 +90,16 @@ export const usePipelinesStore = defineStore('pipelines', () => {
|
|
|
83
90
|
retiredPipelines.value = retired ?? []
|
|
84
91
|
}
|
|
85
92
|
|
|
93
|
+
/**
|
|
94
|
+
* Replace the registered gates' declared config forms from a snapshot. Applied even when EMPTY,
|
|
95
|
+
* for the reason `retired` is: carrying the previous board's forward would offer a form for a
|
|
96
|
+
* parameter this deployment's gates do not declare, and a value saved through it would then be
|
|
97
|
+
* refused at save by the very registry that never declared it.
|
|
98
|
+
*/
|
|
99
|
+
function hydrateGateConfigForms(forms: GateConfigForm[]) {
|
|
100
|
+
gateConfigForms.value = forms
|
|
101
|
+
}
|
|
102
|
+
|
|
86
103
|
function getPipeline(id: string) {
|
|
87
104
|
return pipelines.value.find((p) => p.id === id)
|
|
88
105
|
}
|
|
@@ -117,6 +134,7 @@ export const usePipelinesStore = defineStore('pipelines', () => {
|
|
|
117
134
|
pipelines,
|
|
118
135
|
catalogVersions,
|
|
119
136
|
retiredPipelines,
|
|
137
|
+
gateConfigForms,
|
|
120
138
|
draft,
|
|
121
139
|
draftGates,
|
|
122
140
|
draftEnabled,
|
|
@@ -132,6 +150,7 @@ export const usePipelinesStore = defineStore('pipelines', () => {
|
|
|
132
150
|
draftDescription,
|
|
133
151
|
editingId,
|
|
134
152
|
hydrate,
|
|
153
|
+
hydrateGateConfigForms,
|
|
135
154
|
getPipeline,
|
|
136
155
|
...draftActions,
|
|
137
156
|
...persistence,
|
|
@@ -114,6 +114,9 @@ export function applySnapshotToStores(snapshot: WorkspaceSnapshot, boardSince?:
|
|
|
114
114
|
snapshot.binaryGeneratorsUnavailable === true,
|
|
115
115
|
)
|
|
116
116
|
useTaskTypesStore().hydrateCapabilities(capabilities)
|
|
117
|
+
// The per-step parameters each registered gate declares, so a gated step's config form in the
|
|
118
|
+
// builder comes from the gate's own registration rather than a form hard-coded per gate.
|
|
119
|
+
usePipelinesStore().hydrateGateConfigForms(snapshot.gateConfigForms ?? [])
|
|
117
120
|
// The account's repo-sourced Claude Skills catalog (shared across its workspaces), so the
|
|
118
121
|
// pipeline builder's per-step skill picker has its options. A straight replace.
|
|
119
122
|
useSkillsStore().hydrate(snapshot.skills ?? [])
|
package/app/types/domain.ts
CHANGED
|
@@ -73,6 +73,11 @@ export type {
|
|
|
73
73
|
DescriptorField,
|
|
74
74
|
DescriptorFieldValue,
|
|
75
75
|
DescriptorFieldValues,
|
|
76
|
+
// Per-step GATE configuration: who may resolve a human approval gate, how many of them, and
|
|
77
|
+
// the parameters the step's registered gate declares (`contracts/src/gate-config.ts`).
|
|
78
|
+
GateApproverPolicy,
|
|
79
|
+
GateConfigForm,
|
|
80
|
+
StepGateConfig,
|
|
76
81
|
Pipeline,
|
|
77
82
|
PipelinePurpose,
|
|
78
83
|
SpendStatus,
|
package/i18n/locales/de.json
CHANGED
|
@@ -699,6 +699,7 @@
|
|
|
699
699
|
"neverUsed": "nie verwendet",
|
|
700
700
|
"createdBy": "erstellt von {user}",
|
|
701
701
|
"createdByYou": "Ihnen",
|
|
702
|
+
"createdByKey": "API-Schlüssel {id}",
|
|
702
703
|
"revoke": "Token widerrufen"
|
|
703
704
|
},
|
|
704
705
|
"add": {
|
|
@@ -1985,7 +1986,12 @@
|
|
|
1985
1986
|
"notRun": "nicht ausgeführt",
|
|
1986
1987
|
"attempts": "Versuch {attempts} von {maxAttempts}",
|
|
1987
1988
|
"omittedTestPaths": "{count} deklarierte Testdatei wurde vor dem Nachweis verworfen, daher wurde der Stand vor dem Fix aus einer unvollständigen Reproduktion aufgebaut. | {count} deklarierte Testdateien wurden vor dem Nachweis verworfen, daher wurde der Stand vor dem Fix aus einer unvollständigen Reproduktion aufgebaut."
|
|
1988
|
-
}
|
|
1989
|
+
},
|
|
1990
|
+
"quorumProgress": "{recorded} von {required} Freigaben",
|
|
1991
|
+
"quorumYours": "(deine ist gezählt)",
|
|
1992
|
+
"quorumEditLocked": "Korrekturen sind möglich, sobald deine Freigabe dieses Gate auflöst. Bis dahin unverändert freigeben oder Änderungen anfordern.",
|
|
1993
|
+
"notAnApprover": "Dieses Gate benennt, wer es auflösen darf, und du gehörst nicht dazu.",
|
|
1994
|
+
"approverIdentityRequired": "Dieses Gate benennt, wer es auflösen darf; eine dieser Personen muss dafür angemeldet sein."
|
|
1989
1995
|
},
|
|
1990
1996
|
"inspector": {
|
|
1991
1997
|
"frameStatus": {
|
|
@@ -4129,6 +4135,17 @@
|
|
|
4129
4135
|
"hint": "Der Höchstumfang einer einzelnen Antwort dieses Agenten. Leer lassen heißt vom nächsthöheren Level erben, nicht das Limit aufheben. Der Wert eines Pipeline-Schritts sticht die Vorgabe des Workspace.",
|
|
4130
4136
|
"inherits": "Übernommen",
|
|
4131
4137
|
"inheritsValue": "Übernommen ({tokens})"
|
|
4138
|
+
},
|
|
4139
|
+
"gateConfig": {
|
|
4140
|
+
"approversLabel": "Wer freigeben darf",
|
|
4141
|
+
"roleAdmin": "Administratoren",
|
|
4142
|
+
"roleMember": "Mitglieder",
|
|
4143
|
+
"namedApproversLabel": "Benannte Freigebende",
|
|
4144
|
+
"namedApproversPlaceholder": "Alle mit Schreibrecht",
|
|
4145
|
+
"requiredApprovalsLabel": "Erforderliche Freigaben",
|
|
4146
|
+
"requiredApprovalsHint": "Jeweils von einer anderen Person, bevor der Lauf fortgesetzt wird.",
|
|
4147
|
+
"anyoneHint": "Alle, die dieses Board bearbeiten dürfen, können diesen Schritt freigeben.",
|
|
4148
|
+
"gateParametersLabel": "Gate-Einstellungen"
|
|
4132
4149
|
}
|
|
4133
4150
|
},
|
|
4134
4151
|
"agentPrompt": {
|
package/i18n/locales/en.json
CHANGED
|
@@ -1544,7 +1544,12 @@
|
|
|
1544
1544
|
"attempts": "Attempt {attempts} of {maxAttempts}",
|
|
1545
1545
|
"omittedTestPaths": "{count} declared test file was dropped before the proof ran, so the pre-fix tree was rebuilt from an incomplete reproduction. | {count} declared test files were dropped before the proof ran, so the pre-fix tree was rebuilt from an incomplete reproduction.",
|
|
1546
1546
|
"@omittedTestPaths": "Plural form required. A dropped file can leave the pre-fix tree without the reproduction, which makes the check pass there and wrongly reads as 'the test does not capture the defect'."
|
|
1547
|
-
}
|
|
1547
|
+
},
|
|
1548
|
+
"quorumProgress": "{recorded} of {required} approvals",
|
|
1549
|
+
"quorumYours": "(yours counted)",
|
|
1550
|
+
"quorumEditLocked": "Corrections can be typed once yours is the approval that clears this gate. Until then, approve as-is or request changes.",
|
|
1551
|
+
"notAnApprover": "This gate names who may resolve it, and you are not one of them.",
|
|
1552
|
+
"approverIdentityRequired": "This gate names who may resolve it, so it has to be resolved by one of those people signed in."
|
|
1548
1553
|
},
|
|
1549
1554
|
"inspector": {
|
|
1550
1555
|
"frameStatus": {
|
|
@@ -3185,6 +3190,7 @@
|
|
|
3185
3190
|
"neverUsed": "never used",
|
|
3186
3191
|
"createdBy": "created by {user}",
|
|
3187
3192
|
"createdByYou": "you",
|
|
3193
|
+
"createdByKey": "API key {id}",
|
|
3188
3194
|
"revoke": "Revoke token"
|
|
3189
3195
|
},
|
|
3190
3196
|
"add": {
|
|
@@ -4643,6 +4649,17 @@
|
|
|
4643
4649
|
"hint": "The most a single reply from this agent may run to. Leave it empty to inherit the next level up rather than to lift the limit. A pipeline step's own value wins over the workspace default.",
|
|
4644
4650
|
"inherits": "Inherited",
|
|
4645
4651
|
"inheritsValue": "Inherited ({tokens})"
|
|
4652
|
+
},
|
|
4653
|
+
"gateConfig": {
|
|
4654
|
+
"approversLabel": "Who may approve",
|
|
4655
|
+
"roleAdmin": "Admins",
|
|
4656
|
+
"roleMember": "Members",
|
|
4657
|
+
"namedApproversLabel": "Named approvers",
|
|
4658
|
+
"namedApproversPlaceholder": "Anyone entitled to write",
|
|
4659
|
+
"requiredApprovalsLabel": "Approvals required",
|
|
4660
|
+
"requiredApprovalsHint": "Each from a different person before the run continues.",
|
|
4661
|
+
"anyoneHint": "Anyone who can edit this board may approve this step.",
|
|
4662
|
+
"gateParametersLabel": "Gate settings"
|
|
4646
4663
|
}
|
|
4647
4664
|
},
|
|
4648
4665
|
"agentPrompt": {
|
package/i18n/locales/es.json
CHANGED
|
@@ -1455,7 +1455,12 @@
|
|
|
1455
1455
|
"notRun": "no ejecutado",
|
|
1456
1456
|
"attempts": "Intento {attempts} de {maxAttempts}",
|
|
1457
1457
|
"omittedTestPaths": "Se descartó {count} archivo de prueba declarado antes de ejecutar la prueba, por lo que el árbol previo a la corrección se reconstruyó a partir de una reproducción incompleta. | Se descartaron {count} archivos de prueba declarados antes de ejecutar la prueba, por lo que el árbol previo a la corrección se reconstruyó a partir de una reproducción incompleta."
|
|
1458
|
-
}
|
|
1458
|
+
},
|
|
1459
|
+
"quorumProgress": "{recorded} de {required} aprobaciones",
|
|
1460
|
+
"quorumYours": "(la tuya está contada)",
|
|
1461
|
+
"quorumEditLocked": "Podrás escribir correcciones cuando tu aprobación sea la que libere esta puerta. Hasta entonces, aprueba tal cual o solicita cambios.",
|
|
1462
|
+
"notAnApprover": "Esta compuerta designa quién puede resolverla y tú no estás en la lista.",
|
|
1463
|
+
"approverIdentityRequired": "Esta compuerta designa quién puede resolverla, así que debe resolverla una de esas personas con la sesión iniciada."
|
|
1459
1464
|
},
|
|
1460
1465
|
"inspector": {
|
|
1461
1466
|
"frameStatus": {
|
|
@@ -2937,6 +2942,7 @@
|
|
|
2937
2942
|
"neverUsed": "nunca usado",
|
|
2938
2943
|
"createdBy": "creado por {user}",
|
|
2939
2944
|
"createdByYou": "ti",
|
|
2945
|
+
"createdByKey": "la clave de API {id}",
|
|
2940
2946
|
"revoke": "Revocar token"
|
|
2941
2947
|
},
|
|
2942
2948
|
"add": {
|
|
@@ -4510,6 +4516,17 @@
|
|
|
4510
4516
|
"hint": "El maximo al que puede llegar una sola respuesta de este agente. Dejarlo vacio hereda del nivel superior; no elimina el limite. El valor propio de un paso del pipeline prevalece sobre el predeterminado del espacio de trabajo.",
|
|
4511
4517
|
"inherits": "Heredado",
|
|
4512
4518
|
"inheritsValue": "Heredado ({tokens})"
|
|
4519
|
+
},
|
|
4520
|
+
"gateConfig": {
|
|
4521
|
+
"approversLabel": "Quién puede aprobar",
|
|
4522
|
+
"roleAdmin": "Administradores",
|
|
4523
|
+
"roleMember": "Miembros",
|
|
4524
|
+
"namedApproversLabel": "Aprobadores designados",
|
|
4525
|
+
"namedApproversPlaceholder": "Cualquiera con permiso de escritura",
|
|
4526
|
+
"requiredApprovalsLabel": "Aprobaciones necesarias",
|
|
4527
|
+
"requiredApprovalsHint": "Cada una de una persona distinta antes de que la ejecución continúe.",
|
|
4528
|
+
"anyoneHint": "Cualquiera que pueda editar este tablero puede aprobar este paso.",
|
|
4529
|
+
"gateParametersLabel": "Ajustes de la compuerta"
|
|
4513
4530
|
}
|
|
4514
4531
|
},
|
|
4515
4532
|
"agentPrompt": {
|
package/i18n/locales/fr.json
CHANGED
|
@@ -1455,7 +1455,12 @@
|
|
|
1455
1455
|
"notRun": "non exécuté",
|
|
1456
1456
|
"attempts": "Tentative {attempts} sur {maxAttempts}",
|
|
1457
1457
|
"omittedTestPaths": "{count} fichier de test déclaré a été écarté avant l’exécution de la preuve, l’arbre d’avant le correctif a donc été reconstruit à partir d’une reproduction incomplète. | {count} fichiers de test déclarés ont été écartés avant l’exécution de la preuve, l’arbre d’avant le correctif a donc été reconstruit à partir d’une reproduction incomplète."
|
|
1458
|
-
}
|
|
1458
|
+
},
|
|
1459
|
+
"quorumProgress": "{recorded} approbations sur {required}",
|
|
1460
|
+
"quorumYours": "(la vôtre est comptée)",
|
|
1461
|
+
"quorumEditLocked": "Les corrections seront possibles quand votre approbation sera celle qui libère ce point de contrôle. D'ici là, approuvez tel quel ou demandez des modifications.",
|
|
1462
|
+
"notAnApprover": "Ce contrôle désigne qui peut le lever, et vous n'en faites pas partie.",
|
|
1463
|
+
"approverIdentityRequired": "Ce contrôle désigne qui peut le lever : l'une de ces personnes doit être connectée pour le faire."
|
|
1459
1464
|
},
|
|
1460
1465
|
"inspector": {
|
|
1461
1466
|
"frameStatus": {
|
|
@@ -2937,6 +2942,7 @@
|
|
|
2937
2942
|
"neverUsed": "jamais utilisé",
|
|
2938
2943
|
"createdBy": "créé par {user}",
|
|
2939
2944
|
"createdByYou": "vous",
|
|
2945
|
+
"createdByKey": "la clé d’API {id}",
|
|
2940
2946
|
"revoke": "Révoquer le jeton"
|
|
2941
2947
|
},
|
|
2942
2948
|
"add": {
|
|
@@ -4510,6 +4516,17 @@
|
|
|
4510
4516
|
"hint": "La longueur maximale d'une seule reponse de cet agent. Laisser vide herite du niveau superieur, cela ne leve pas la limite. La valeur propre a une etape du pipeline l'emporte sur la valeur par defaut de l'espace de travail.",
|
|
4511
4517
|
"inherits": "Hérité",
|
|
4512
4518
|
"inheritsValue": "Hérité ({tokens})"
|
|
4519
|
+
},
|
|
4520
|
+
"gateConfig": {
|
|
4521
|
+
"approversLabel": "Qui peut approuver",
|
|
4522
|
+
"roleAdmin": "Administrateurs",
|
|
4523
|
+
"roleMember": "Membres",
|
|
4524
|
+
"namedApproversLabel": "Approbateurs désignés",
|
|
4525
|
+
"namedApproversPlaceholder": "Toute personne autorisée à écrire",
|
|
4526
|
+
"requiredApprovalsLabel": "Approbations requises",
|
|
4527
|
+
"requiredApprovalsHint": "Chacune d'une personne différente avant que l'exécution reprenne.",
|
|
4528
|
+
"anyoneHint": "Toute personne pouvant modifier ce tableau peut approuver cette étape.",
|
|
4529
|
+
"gateParametersLabel": "Paramètres du contrôle"
|
|
4513
4530
|
}
|
|
4514
4531
|
},
|
|
4515
4532
|
"agentPrompt": {
|
package/i18n/locales/he.json
CHANGED
|
@@ -1455,7 +1455,12 @@
|
|
|
1455
1455
|
"notRun": "לא הורץ",
|
|
1456
1456
|
"attempts": "ניסיון {attempts} מתוך {maxAttempts}",
|
|
1457
1457
|
"omittedTestPaths": "קובץ בדיקה אחד שהוצהר הושמט לפני הרצת ההוכחה, ולכן העץ שלפני התיקון נבנה משחזור חלקי. | שני קובצי בדיקה שהוצהרו הושמטו לפני הרצת ההוכחה, ולכן העץ שלפני התיקון נבנה משחזור חלקי. | {count} קובצי בדיקה שהוצהרו הושמטו לפני הרצת ההוכחה, ולכן העץ שלפני התיקון נבנה משחזור חלקי."
|
|
1458
|
-
}
|
|
1458
|
+
},
|
|
1459
|
+
"quorumProgress": "{recorded} מתוך {required} אישורים",
|
|
1460
|
+
"quorumYours": "(שלך נספר)",
|
|
1461
|
+
"quorumEditLocked": "אפשר להקליד תיקונים כאשר האישור שלך יהיה זה שפותח את השער. עד אז, אשר כמות שהוא או בקש שינויים.",
|
|
1462
|
+
"notAnApprover": "השער הזה מגדיר מי רשאי לפתור אותו, ואינך אחד מהם.",
|
|
1463
|
+
"approverIdentityRequired": "השער הזה מגדיר מי רשאי לפתור אותו, ולכן אחד מאותם אנשים חייב להיות מחובר."
|
|
1459
1464
|
},
|
|
1460
1465
|
"inspector": {
|
|
1461
1466
|
"frameStatus": {
|
|
@@ -3078,6 +3083,7 @@
|
|
|
3078
3083
|
"neverUsed": "מעולם לא היה בשימוש",
|
|
3079
3084
|
"createdBy": "נוצר על ידי {user}",
|
|
3080
3085
|
"createdByYou": "אתה",
|
|
3086
|
+
"createdByKey": "מפתח API {id}",
|
|
3081
3087
|
"revoke": "בטל אסימון"
|
|
3082
3088
|
},
|
|
3083
3089
|
"add": {
|
|
@@ -4510,6 +4516,17 @@
|
|
|
4510
4516
|
"hint": "המקסימום לתשובה בודדת של הסוכן הזה. השארה ריקה יורשת מהרמה שמעל, ואינה מבטלת את המגבלה. ערך של שלב בצינור גובר על ברירת המחדל של סביבת העבודה.",
|
|
4511
4517
|
"inherits": "בירושה",
|
|
4512
4518
|
"inheritsValue": "בירושה ({tokens})"
|
|
4519
|
+
},
|
|
4520
|
+
"gateConfig": {
|
|
4521
|
+
"approversLabel": "מי רשאי לאשר",
|
|
4522
|
+
"roleAdmin": "מנהלים",
|
|
4523
|
+
"roleMember": "חברים",
|
|
4524
|
+
"namedApproversLabel": "מאשרים ייעודיים",
|
|
4525
|
+
"namedApproversPlaceholder": "כל מי שרשאי לערוך",
|
|
4526
|
+
"requiredApprovalsLabel": "אישורים נדרשים",
|
|
4527
|
+
"requiredApprovalsHint": "כל אחד מאדם אחר, לפני שההרצה ממשיכה.",
|
|
4528
|
+
"anyoneHint": "כל מי שיכול לערוך את הלוח הזה רשאי לאשר את השלב.",
|
|
4529
|
+
"gateParametersLabel": "הגדרות השער"
|
|
4513
4530
|
}
|
|
4514
4531
|
},
|
|
4515
4532
|
"agentPrompt": {
|
package/i18n/locales/it.json
CHANGED
|
@@ -699,6 +699,7 @@
|
|
|
699
699
|
"neverUsed": "mai utilizzato",
|
|
700
700
|
"createdBy": "creato da {user}",
|
|
701
701
|
"createdByYou": "te",
|
|
702
|
+
"createdByKey": "la chiave API {id}",
|
|
702
703
|
"revoke": "Revoca token"
|
|
703
704
|
},
|
|
704
705
|
"add": {
|
|
@@ -1985,7 +1986,12 @@
|
|
|
1985
1986
|
"notRun": "non eseguito",
|
|
1986
1987
|
"attempts": "Tentativo {attempts} di {maxAttempts}",
|
|
1987
1988
|
"omittedTestPaths": "{count} file di test dichiarato è stato scartato prima dell’esecuzione della prova, quindi l’albero precedente alla correzione è stato ricostruito da una riproduzione incompleta. | {count} file di test dichiarati sono stati scartati prima dell’esecuzione della prova, quindi l’albero precedente alla correzione è stato ricostruito da una riproduzione incompleta."
|
|
1988
|
-
}
|
|
1989
|
+
},
|
|
1990
|
+
"quorumProgress": "{recorded} di {required} approvazioni",
|
|
1991
|
+
"quorumYours": "(la tua è conteggiata)",
|
|
1992
|
+
"quorumEditLocked": "Le correzioni si potranno scrivere quando la tua approvazione sarà quella che sblocca questo gate. Fino ad allora, approva così com'è o richiedi modifiche.",
|
|
1993
|
+
"notAnApprover": "Questo gate indica chi può risolverlo e tu non sei tra loro.",
|
|
1994
|
+
"approverIdentityRequired": "Questo gate indica chi può risolverlo, quindi deve farlo una di quelle persone dopo aver effettuato l’accesso."
|
|
1989
1995
|
},
|
|
1990
1996
|
"inspector": {
|
|
1991
1997
|
"frameStatus": {
|
|
@@ -4129,6 +4135,17 @@
|
|
|
4129
4135
|
"hint": "Il massimo a cui puo arrivare una singola risposta di questo agente. Lasciarlo vuoto eredita dal livello superiore, non toglie il limite. Il valore di uno step della pipeline prevale sul predefinito dello spazio di lavoro.",
|
|
4130
4136
|
"inherits": "Ereditato",
|
|
4131
4137
|
"inheritsValue": "Ereditato ({tokens})"
|
|
4138
|
+
},
|
|
4139
|
+
"gateConfig": {
|
|
4140
|
+
"approversLabel": "Chi può approvare",
|
|
4141
|
+
"roleAdmin": "Amministratori",
|
|
4142
|
+
"roleMember": "Membri",
|
|
4143
|
+
"namedApproversLabel": "Approvatori designati",
|
|
4144
|
+
"namedApproversPlaceholder": "Chiunque abbia permessi di scrittura",
|
|
4145
|
+
"requiredApprovalsLabel": "Approvazioni richieste",
|
|
4146
|
+
"requiredApprovalsHint": "Ciascuna da una persona diversa prima che l'esecuzione prosegua.",
|
|
4147
|
+
"anyoneHint": "Chiunque possa modificare questa board può approvare questo passo.",
|
|
4148
|
+
"gateParametersLabel": "Impostazioni del gate"
|
|
4132
4149
|
}
|
|
4133
4150
|
},
|
|
4134
4151
|
"agentPrompt": {
|
package/i18n/locales/ja.json
CHANGED
|
@@ -1455,7 +1455,12 @@
|
|
|
1455
1455
|
"notRun": "未実行",
|
|
1456
1456
|
"attempts": "{maxAttempts} 回中 {attempts} 回目の試行",
|
|
1457
1457
|
"omittedTestPaths": "宣言されたテストファイル {count} 件が証跡の実行前に除外されたため、修正前のツリーは不完全な再現から再構築されました。 | 宣言されたテストファイル {count} 件が証跡の実行前に除外されたため、修正前のツリーは不完全な再現から再構築されました。"
|
|
1458
|
-
}
|
|
1458
|
+
},
|
|
1459
|
+
"quorumProgress": "承認 {recorded} / {required}",
|
|
1460
|
+
"quorumYours": "(あなたの承認は集計済み)",
|
|
1461
|
+
"quorumEditLocked": "このゲートを解除する承認があなたのものになった時点で、修正を入力できます。それまでは、そのまま承認するか変更を依頼してください。",
|
|
1462
|
+
"notAnApprover": "このゲートは解除できる人を指定しており、あなたは含まれていません。",
|
|
1463
|
+
"approverIdentityRequired": "このゲートは解除できる人を指定しているため、その人がサインインして解除する必要があります。"
|
|
1459
1464
|
},
|
|
1460
1465
|
"inspector": {
|
|
1461
1466
|
"frameStatus": {
|
|
@@ -3078,6 +3083,7 @@
|
|
|
3078
3083
|
"neverUsed": "未使用",
|
|
3079
3084
|
"createdBy": "作成者: {user}",
|
|
3080
3085
|
"createdByYou": "あなた",
|
|
3086
|
+
"createdByKey": "APIキー {id}",
|
|
3081
3087
|
"revoke": "トークンを取り消す"
|
|
3082
3088
|
},
|
|
3083
3089
|
"add": {
|
|
@@ -4510,6 +4516,17 @@
|
|
|
4510
4516
|
"hint": "このエージェントの1回の応答の上限です。空欄にすると上位の設定を継承します。上限が無くなるわけではありません。パイプラインのステップに設定した値はワークスペースの既定値より優先されます。",
|
|
4511
4517
|
"inherits": "継承",
|
|
4512
4518
|
"inheritsValue": "継承({tokens})"
|
|
4519
|
+
},
|
|
4520
|
+
"gateConfig": {
|
|
4521
|
+
"approversLabel": "承認できる人",
|
|
4522
|
+
"roleAdmin": "管理者",
|
|
4523
|
+
"roleMember": "メンバー",
|
|
4524
|
+
"namedApproversLabel": "指名した承認者",
|
|
4525
|
+
"namedApproversPlaceholder": "書き込み権限のある全員",
|
|
4526
|
+
"requiredApprovalsLabel": "必要な承認数",
|
|
4527
|
+
"requiredApprovalsHint": "実行を再開する前に、それぞれ別の人からの承認が必要です。",
|
|
4528
|
+
"anyoneHint": "このボードを編集できる人なら誰でもこのステップを承認できます。",
|
|
4529
|
+
"gateParametersLabel": "ゲートの設定"
|
|
4513
4530
|
}
|
|
4514
4531
|
},
|
|
4515
4532
|
"agentPrompt": {
|
package/i18n/locales/pl.json
CHANGED
|
@@ -1455,7 +1455,12 @@
|
|
|
1455
1455
|
"notRun": "nie uruchomiono",
|
|
1456
1456
|
"attempts": "Próba {attempts} z {maxAttempts}",
|
|
1457
1457
|
"omittedTestPaths": "Przed uruchomieniem dowodu pominięto {count} zadeklarowany plik testowy, więc drzewo sprzed poprawki odtworzono z niepełnej reprodukcji. | Przed uruchomieniem dowodu pominięto {count} zadeklarowane pliki testowe, więc drzewo sprzed poprawki odtworzono z niepełnej reprodukcji. | Przed uruchomieniem dowodu pominięto {count} zadeklarowanych plików testowych, więc drzewo sprzed poprawki odtworzono z niepełnej reprodukcji."
|
|
1458
|
-
}
|
|
1458
|
+
},
|
|
1459
|
+
"quorumProgress": "{recorded} z {required} zatwierdzeń",
|
|
1460
|
+
"quorumYours": "(twoje jest policzone)",
|
|
1461
|
+
"quorumEditLocked": "Poprawki będzie można wpisać, gdy Twoja akceptacja odblokuje tę bramkę. Do tego czasu zatwierdź bez zmian lub poproś o zmiany.",
|
|
1462
|
+
"notAnApprover": "Ta bramka wskazuje, kto może ją rozstrzygnąć, a ciebie na tej liście nie ma.",
|
|
1463
|
+
"approverIdentityRequired": "Ta bramka wskazuje, kto może ją rozstrzygnąć, więc musi to zrobić jedna z tych osób po zalogowaniu."
|
|
1459
1464
|
},
|
|
1460
1465
|
"inspector": {
|
|
1461
1466
|
"frameStatus": {
|
|
@@ -2937,6 +2942,7 @@
|
|
|
2937
2942
|
"neverUsed": "nigdy nie użyto",
|
|
2938
2943
|
"createdBy": "utworzone przez {user}",
|
|
2939
2944
|
"createdByYou": "Ciebie",
|
|
2945
|
+
"createdByKey": "klucz API {id}",
|
|
2940
2946
|
"revoke": "Unieważnij token"
|
|
2941
2947
|
},
|
|
2942
2948
|
"add": {
|
|
@@ -4510,6 +4516,17 @@
|
|
|
4510
4516
|
"hint": "Maksymalna długość pojedynczej odpowiedzi tego agenta. Puste pole dziedziczy wartość z wyższego poziomu, a nie znosi limitu. Wartość ustawiona na kroku pipeline'u ma pierwszeństwo przed domyślną wartością obszaru roboczego.",
|
|
4511
4517
|
"inherits": "Odziedziczone",
|
|
4512
4518
|
"inheritsValue": "Odziedziczone ({tokens})"
|
|
4519
|
+
},
|
|
4520
|
+
"gateConfig": {
|
|
4521
|
+
"approversLabel": "Kto może zatwierdzić",
|
|
4522
|
+
"roleAdmin": "Administratorzy",
|
|
4523
|
+
"roleMember": "Członkowie",
|
|
4524
|
+
"namedApproversLabel": "Wskazane osoby zatwierdzające",
|
|
4525
|
+
"namedApproversPlaceholder": "Każdy z prawem zapisu",
|
|
4526
|
+
"requiredApprovalsLabel": "Wymagane zatwierdzenia",
|
|
4527
|
+
"requiredApprovalsHint": "Każde od innej osoby, zanim przebieg ruszy dalej.",
|
|
4528
|
+
"anyoneHint": "Każdy, kto może edytować tę tablicę, może zatwierdzić ten krok.",
|
|
4529
|
+
"gateParametersLabel": "Ustawienia bramki"
|
|
4513
4530
|
}
|
|
4514
4531
|
},
|
|
4515
4532
|
"agentPrompt": {
|
package/i18n/locales/tr.json
CHANGED
|
@@ -1455,7 +1455,12 @@
|
|
|
1455
1455
|
"notRun": "çalıştırılmadı",
|
|
1456
1456
|
"attempts": "{maxAttempts} denemeden {attempts}. deneme",
|
|
1457
1457
|
"omittedTestPaths": "Kanıt çalıştırılmadan önce bildirilen {count} test dosyası atıldı; bu yüzden düzeltme öncesi ağaç eksik bir yeniden üretimden kuruldu. | Kanıt çalıştırılmadan önce bildirilen {count} test dosyası atıldı; bu yüzden düzeltme öncesi ağaç eksik bir yeniden üretimden kuruldu."
|
|
1458
|
-
}
|
|
1458
|
+
},
|
|
1459
|
+
"quorumProgress": "{required} onaydan {recorded} tanesi",
|
|
1460
|
+
"quorumYours": "(seninki sayıldı)",
|
|
1461
|
+
"quorumEditLocked": "Bu geçidi açan onay sizinki olduğunda düzeltme yazabilirsiniz. O ana kadar olduğu gibi onaylayın ya da değişiklik isteyin.",
|
|
1462
|
+
"notAnApprover": "Bu kapı kimlerin karar verebileceğini belirtiyor ve sen bunlardan biri değilsin.",
|
|
1463
|
+
"approverIdentityRequired": "Bu kapı kimlerin karar verebileceğini belirtiyor; bu kişilerden biri oturum açarak karar vermeli."
|
|
1459
1464
|
},
|
|
1460
1465
|
"inspector": {
|
|
1461
1466
|
"frameStatus": {
|
|
@@ -3078,6 +3083,7 @@
|
|
|
3078
3083
|
"neverUsed": "hiç kullanılmadı",
|
|
3079
3084
|
"createdBy": "oluşturan: {user}",
|
|
3080
3085
|
"createdByYou": "siz",
|
|
3086
|
+
"createdByKey": "{id} API anahtarı",
|
|
3081
3087
|
"revoke": "Belirteci iptal et"
|
|
3082
3088
|
},
|
|
3083
3089
|
"add": {
|
|
@@ -4510,6 +4516,17 @@
|
|
|
4510
4516
|
"hint": "Bu ajanın tek bir yanıtının ulaşabileceği üst sınır. Boş bırakmak sınırı kaldırmaz, bir üst seviyeden devralır. Pipeline adımının kendi değeri çalışma alanı varsayılanını geçersiz kılar.",
|
|
4511
4517
|
"inherits": "Devralındı",
|
|
4512
4518
|
"inheritsValue": "Devralındı ({tokens})"
|
|
4519
|
+
},
|
|
4520
|
+
"gateConfig": {
|
|
4521
|
+
"approversLabel": "Kimler onaylayabilir",
|
|
4522
|
+
"roleAdmin": "Yöneticiler",
|
|
4523
|
+
"roleMember": "Üyeler",
|
|
4524
|
+
"namedApproversLabel": "Adı geçen onaylayıcılar",
|
|
4525
|
+
"namedApproversPlaceholder": "Yazma yetkisi olan herkes",
|
|
4526
|
+
"requiredApprovalsLabel": "Gereken onay sayısı",
|
|
4527
|
+
"requiredApprovalsHint": "Çalışma devam etmeden önce her biri farklı bir kişiden.",
|
|
4528
|
+
"anyoneHint": "Bu panoyu düzenleyebilen herkes bu adımı onaylayabilir.",
|
|
4529
|
+
"gateParametersLabel": "Kapı ayarları"
|
|
4513
4530
|
}
|
|
4514
4531
|
},
|
|
4515
4532
|
"agentPrompt": {
|
package/i18n/locales/uk.json
CHANGED
|
@@ -1455,7 +1455,12 @@
|
|
|
1455
1455
|
"notRun": "не запускалося",
|
|
1456
1456
|
"attempts": "Спроба {attempts} з {maxAttempts}",
|
|
1457
1457
|
"omittedTestPaths": "Перед запуском доказу пропущено {count} оголошений тестовий файл, тож дерево до виправлення відтворено з неповної репродукції. | Перед запуском доказу пропущено {count} оголошені тестові файли, тож дерево до виправлення відтворено з неповної репродукції. | Перед запуском доказу пропущено {count} оголошених тестових файлів, тож дерево до виправлення відтворено з неповної репродукції."
|
|
1458
|
-
}
|
|
1458
|
+
},
|
|
1459
|
+
"quorumProgress": "{recorded} із {required} схвалень",
|
|
1460
|
+
"quorumYours": "(твоє враховано)",
|
|
1461
|
+
"quorumEditLocked": "Виправлення можна буде ввести, коли саме твоє схвалення відкриє цей шлюз. До того часу схвали як є або попроси зміни.",
|
|
1462
|
+
"notAnApprover": "Цей шлюз називає, хто може його розв’язати, і тебе серед них немає.",
|
|
1463
|
+
"approverIdentityRequired": "Цей шлюз називає, хто може його розв’язати, тож це має зробити одна з тих людей, увійшовши в систему."
|
|
1459
1464
|
},
|
|
1460
1465
|
"inspector": {
|
|
1461
1466
|
"frameStatus": {
|
|
@@ -2937,6 +2942,7 @@
|
|
|
2937
2942
|
"neverUsed": "ніколи не використовувався",
|
|
2938
2943
|
"createdBy": "створено {user}",
|
|
2939
2944
|
"createdByYou": "вами",
|
|
2945
|
+
"createdByKey": "ключ API {id}",
|
|
2940
2946
|
"revoke": "Відкликати токен"
|
|
2941
2947
|
},
|
|
2942
2948
|
"add": {
|
|
@@ -4510,6 +4516,17 @@
|
|
|
4510
4516
|
"hint": "Максимум для однієї відповіді цього агента. Порожнє поле успадковує значення з вищого рівня, а не знімає обмеження. Значення кроку пайплайна має перевагу над типовим значенням робочого простору.",
|
|
4511
4517
|
"inherits": "Успадковано",
|
|
4512
4518
|
"inheritsValue": "Успадковано ({tokens})"
|
|
4519
|
+
},
|
|
4520
|
+
"gateConfig": {
|
|
4521
|
+
"approversLabel": "Хто може схвалити",
|
|
4522
|
+
"roleAdmin": "Адміністратори",
|
|
4523
|
+
"roleMember": "Учасники",
|
|
4524
|
+
"namedApproversLabel": "Названі схвалювачі",
|
|
4525
|
+
"namedApproversPlaceholder": "Будь-хто з правом запису",
|
|
4526
|
+
"requiredApprovalsLabel": "Потрібно схвалень",
|
|
4527
|
+
"requiredApprovalsHint": "Кожне від іншої людини, перш ніж запуск продовжиться.",
|
|
4528
|
+
"anyoneHint": "Будь-хто, хто може редагувати цю дошку, може схвалити цей крок.",
|
|
4529
|
+
"gateParametersLabel": "Налаштування шлюзу"
|
|
4513
4530
|
}
|
|
4514
4531
|
},
|
|
4515
4532
|
"agentPrompt": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cat-factory/app",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.225.0",
|
|
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.242.0"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@toad-contracts/testing": "0.3.2",
|