@cat-factory/app 0.87.5 → 0.88.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/board/RecurringPipelineModal.vue +162 -2
- package/app/components/initiative/InitiativeTrackerWindow.vue +249 -11
- package/app/components/panels/MergerResultView.vue +1 -0
- package/app/composables/api/initiative.ts +51 -0
- package/app/stores/initiative.ts +82 -1
- package/app/types/initiative.ts +3 -0
- package/app/types/recurring.ts +1 -0
- package/app/utils/catalog.ts +6 -4
- package/app/utils/initiative.ts +27 -4
- package/i18n/locales/en.json +33 -2
- package/i18n/locales/es.json +33 -2
- package/i18n/locales/fr.json +33 -2
- package/i18n/locales/he.json +33 -2
- package/i18n/locales/ja.json +33 -2
- package/i18n/locales/pl.json +33 -2
- package/i18n/locales/tr.json +33 -2
- package/i18n/locales/uk.json +33 -2
- package/package.json +2 -2
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
// task block inside the frame that the schedule re-runs. When the Tech-debt
|
|
6
6
|
// pipeline is picked, the workspace issue-tracker choice is surfaced inline (it is
|
|
7
7
|
// where that pipeline files its ticket) and saved alongside.
|
|
8
|
-
import type { Recurrence, ScheduleTemplate } from '~/types/recurring'
|
|
8
|
+
import type { IssueIntakeConfig, Recurrence, ScheduleTemplate } from '~/types/recurring'
|
|
9
|
+
import type { TaskSourceKind } from '~/types/domain'
|
|
9
10
|
import { pipelineAllowedForSchedule } from '~/utils/pipeline'
|
|
10
11
|
|
|
11
12
|
const ui = useUiStore()
|
|
@@ -13,6 +14,7 @@ const board = useBoardStore()
|
|
|
13
14
|
const pipelines = usePipelinesStore()
|
|
14
15
|
const recurring = useRecurringPipelinesStore()
|
|
15
16
|
const tracker = useTrackerStore()
|
|
17
|
+
const tasks = useTasksStore()
|
|
16
18
|
const toast = useToast()
|
|
17
19
|
const { t } = useI18n()
|
|
18
20
|
|
|
@@ -41,6 +43,17 @@ const trackerKind = ref<'github' | 'jira' | 'linear' | null>(null)
|
|
|
41
43
|
const jiraProjectKey = ref('')
|
|
42
44
|
const linearTeamId = ref('')
|
|
43
45
|
|
|
46
|
+
// Issue-intake config (only relevant when the picked pipeline has a `bug-intake` step). Which
|
|
47
|
+
// tracker board + predicates a recurring bug-triage run pulls its one issue from, per-schedule.
|
|
48
|
+
const intakeSource = ref<TaskSourceKind | null>(null)
|
|
49
|
+
const intakeJiraProjectKey = ref('')
|
|
50
|
+
const intakeLinearTeamId = ref('')
|
|
51
|
+
const intakeGithubRepo = ref('')
|
|
52
|
+
const intakeTitleFragment = ref('')
|
|
53
|
+
const intakeLabels = ref('') // comma-separated in the UI, sent as an array
|
|
54
|
+
const intakeIssueType = ref('')
|
|
55
|
+
const intakeInProgressLabel = ref('')
|
|
56
|
+
|
|
44
57
|
function defaultRecurrence(): Recurrence {
|
|
45
58
|
return {
|
|
46
59
|
intervalHours: 168, // weekly
|
|
@@ -77,6 +90,19 @@ const template = computed<ScheduleTemplate>(() => {
|
|
|
77
90
|
})
|
|
78
91
|
const isTechDebt = computed(() => template.value === 'tech-debt')
|
|
79
92
|
|
|
93
|
+
// A pipeline whose ENABLED steps include `bug-intake` pulls its work from the tracker board, so
|
|
94
|
+
// the intake config is surfaced + required. Mirrors the backend `pipelineHasEnabledBugIntake`
|
|
95
|
+
// (a disabled step imposes nothing), so the modal doesn't demand config for a step that won't run.
|
|
96
|
+
const isBugIntake = computed(() => {
|
|
97
|
+
const pipeline = selectedPipeline.value
|
|
98
|
+
if (!pipeline) return false
|
|
99
|
+
return pipeline.agentKinds.some(
|
|
100
|
+
(kind, i) => kind === 'bug-intake' && pipeline.enabled?.[i] !== false,
|
|
101
|
+
)
|
|
102
|
+
})
|
|
103
|
+
// Sources that can back intake right now (connected / App-installed AND enabled).
|
|
104
|
+
const intakeSources = computed(() => tasks.offeredSources)
|
|
105
|
+
|
|
80
106
|
watch(open, (isOpen) => {
|
|
81
107
|
if (!isOpen) return
|
|
82
108
|
name.value = ''
|
|
@@ -92,9 +118,62 @@ watch(open, (isOpen) => {
|
|
|
92
118
|
trackerKind.value = tracker.settings.tracker
|
|
93
119
|
jiraProjectKey.value = tracker.settings.jiraProjectKey ?? ''
|
|
94
120
|
linearTeamId.value = tracker.settings.linearTeamId ?? ''
|
|
121
|
+
intakeSource.value = null
|
|
122
|
+
intakeJiraProjectKey.value = ''
|
|
123
|
+
intakeLinearTeamId.value = ''
|
|
124
|
+
intakeGithubRepo.value = ''
|
|
125
|
+
intakeTitleFragment.value = ''
|
|
126
|
+
intakeLabels.value = ''
|
|
127
|
+
intakeIssueType.value = ''
|
|
128
|
+
intakeInProgressLabel.value = ''
|
|
129
|
+
// Load the connected task sources so the intake source picker is populated.
|
|
130
|
+
void tasks.probe()
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
// The board field required for the picked source must be filled before a bug-intake schedule saves.
|
|
134
|
+
const intakeReady = computed(() => {
|
|
135
|
+
if (!isBugIntake.value) return true
|
|
136
|
+
if (intakeSource.value === 'jira') return intakeJiraProjectKey.value.trim().length > 0
|
|
137
|
+
if (intakeSource.value === 'linear') return intakeLinearTeamId.value.trim().length > 0
|
|
138
|
+
if (intakeSource.value === 'github') return intakeGithubRepo.value.trim().length > 0
|
|
139
|
+
return false
|
|
95
140
|
})
|
|
96
141
|
|
|
97
|
-
|
|
142
|
+
function buildIssueIntake(): IssueIntakeConfig {
|
|
143
|
+
const source = intakeSource.value as TaskSourceKind
|
|
144
|
+
const labels = intakeLabels.value
|
|
145
|
+
.split(',')
|
|
146
|
+
.map((l) => l.trim())
|
|
147
|
+
.filter(Boolean)
|
|
148
|
+
return {
|
|
149
|
+
source,
|
|
150
|
+
board: {
|
|
151
|
+
...(source === 'jira' && intakeJiraProjectKey.value.trim()
|
|
152
|
+
? { jiraProjectKey: intakeJiraProjectKey.value.trim() }
|
|
153
|
+
: {}),
|
|
154
|
+
...(source === 'linear' && intakeLinearTeamId.value.trim()
|
|
155
|
+
? { linearTeamId: intakeLinearTeamId.value.trim() }
|
|
156
|
+
: {}),
|
|
157
|
+
...(source === 'github' && intakeGithubRepo.value.trim()
|
|
158
|
+
? { githubRepo: intakeGithubRepo.value.trim() }
|
|
159
|
+
: {}),
|
|
160
|
+
},
|
|
161
|
+
predicates: {
|
|
162
|
+
...(intakeTitleFragment.value.trim()
|
|
163
|
+
? { titleFragment: intakeTitleFragment.value.trim() }
|
|
164
|
+
: {}),
|
|
165
|
+
...(labels.length ? { labels } : {}),
|
|
166
|
+
...(intakeIssueType.value.trim() ? { issueType: intakeIssueType.value.trim() } : {}),
|
|
167
|
+
},
|
|
168
|
+
...(source === 'github' && intakeInProgressLabel.value.trim()
|
|
169
|
+
? { inProgressLabel: intakeInProgressLabel.value.trim() }
|
|
170
|
+
: {}),
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const canAdd = computed(
|
|
175
|
+
() => name.value.trim().length > 0 && pipelineId.value.length > 0 && intakeReady.value,
|
|
176
|
+
)
|
|
98
177
|
|
|
99
178
|
async function add() {
|
|
100
179
|
const frameId = ui.addRecurringFrameId
|
|
@@ -119,6 +198,7 @@ async function add() {
|
|
|
119
198
|
onDemand: onDemand.value,
|
|
120
199
|
...(onDemand.value ? {} : { recurrence: recurrence.value }),
|
|
121
200
|
...(description.value.trim() ? { description: description.value.trim() } : {}),
|
|
201
|
+
...(isBugIntake.value ? { issueIntake: buildIssueIntake() } : {}),
|
|
122
202
|
})
|
|
123
203
|
ui.closeAddRecurring()
|
|
124
204
|
} catch (e) {
|
|
@@ -238,6 +318,86 @@ async function add() {
|
|
|
238
318
|
</UFormField>
|
|
239
319
|
</div>
|
|
240
320
|
|
|
321
|
+
<div v-if="isBugIntake" class="space-y-3 rounded-lg border border-slate-800 p-3">
|
|
322
|
+
<p class="text-[11px] font-semibold uppercase tracking-wide text-slate-400">
|
|
323
|
+
{{ t('board.recurring.intake') }}
|
|
324
|
+
</p>
|
|
325
|
+
<p class="text-[11px] text-slate-500">
|
|
326
|
+
{{ t('board.recurring.intakeHint') }}
|
|
327
|
+
</p>
|
|
328
|
+
<p v-if="intakeSources.length === 0" class="text-[11px] text-amber-500">
|
|
329
|
+
{{ t('board.recurring.intakeNoSources') }}
|
|
330
|
+
</p>
|
|
331
|
+
<div v-else class="flex flex-wrap gap-1">
|
|
332
|
+
<UButton
|
|
333
|
+
v-for="s in intakeSources"
|
|
334
|
+
:key="s.source"
|
|
335
|
+
size="xs"
|
|
336
|
+
:color="intakeSource === s.source ? 'primary' : 'neutral'"
|
|
337
|
+
:variant="intakeSource === s.source ? 'solid' : 'subtle'"
|
|
338
|
+
:icon="s.icon"
|
|
339
|
+
@click="intakeSource = s.source"
|
|
340
|
+
>
|
|
341
|
+
{{ s.label }}
|
|
342
|
+
</UButton>
|
|
343
|
+
</div>
|
|
344
|
+
|
|
345
|
+
<UFormField
|
|
346
|
+
v-if="intakeSource === 'jira'"
|
|
347
|
+
:label="t('board.recurring.jiraProjectKey')"
|
|
348
|
+
required
|
|
349
|
+
>
|
|
350
|
+
<UInput
|
|
351
|
+
v-model="intakeJiraProjectKey"
|
|
352
|
+
:placeholder="t('board.recurring.jiraProjectKeyPlaceholder')"
|
|
353
|
+
class="w-full"
|
|
354
|
+
/>
|
|
355
|
+
</UFormField>
|
|
356
|
+
<UFormField
|
|
357
|
+
v-if="intakeSource === 'linear'"
|
|
358
|
+
:label="t('board.recurring.linearTeamId')"
|
|
359
|
+
required
|
|
360
|
+
>
|
|
361
|
+
<UInput v-model="intakeLinearTeamId" placeholder="team_…" class="w-full" />
|
|
362
|
+
</UFormField>
|
|
363
|
+
<UFormField
|
|
364
|
+
v-if="intakeSource === 'github'"
|
|
365
|
+
:label="t('board.recurring.intakeGithubRepo')"
|
|
366
|
+
required
|
|
367
|
+
>
|
|
368
|
+
<!-- A GitHub repo ref is always the literal `owner/name` path, never localized. -->
|
|
369
|
+
<UInput v-model="intakeGithubRepo" placeholder="owner/name" class="w-full" />
|
|
370
|
+
</UFormField>
|
|
371
|
+
|
|
372
|
+
<template v-if="intakeSource">
|
|
373
|
+
<UFormField :label="t('board.recurring.intakeTitleFragment')">
|
|
374
|
+
<UInput
|
|
375
|
+
v-model="intakeTitleFragment"
|
|
376
|
+
:placeholder="t('board.recurring.intakeTitleFragmentPlaceholder')"
|
|
377
|
+
class="w-full"
|
|
378
|
+
/>
|
|
379
|
+
</UFormField>
|
|
380
|
+
<UFormField :label="t('board.recurring.intakeLabels')">
|
|
381
|
+
<UInput
|
|
382
|
+
v-model="intakeLabels"
|
|
383
|
+
:placeholder="t('board.recurring.intakeLabelsPlaceholder')"
|
|
384
|
+
class="w-full"
|
|
385
|
+
/>
|
|
386
|
+
</UFormField>
|
|
387
|
+
<UFormField :label="t('board.recurring.intakeIssueType')">
|
|
388
|
+
<!-- A literal issue-type example (tracker vocabulary), kept verbatim across locales. -->
|
|
389
|
+
<UInput v-model="intakeIssueType" placeholder="bug" class="w-full" />
|
|
390
|
+
</UFormField>
|
|
391
|
+
<UFormField
|
|
392
|
+
v-if="intakeSource === 'github'"
|
|
393
|
+
:label="t('board.recurring.intakeInProgressLabel')"
|
|
394
|
+
>
|
|
395
|
+
<!-- A literal label example, kept verbatim across locales. -->
|
|
396
|
+
<UInput v-model="intakeInProgressLabel" placeholder="in-progress" class="w-full" />
|
|
397
|
+
</UFormField>
|
|
398
|
+
</template>
|
|
399
|
+
</div>
|
|
400
|
+
|
|
241
401
|
<p class="text-[11px] text-slate-500">
|
|
242
402
|
{{ t('board.recurring.footerHint') }}
|
|
243
403
|
</p>
|
|
@@ -7,9 +7,11 @@
|
|
|
7
7
|
// result-view host: from the board card / inspector (`ui.openInitiativeTracker`) or
|
|
8
8
|
// as the planner step's result view. Live `initiative` stream events patch the
|
|
9
9
|
// store, so an open window follows the plan as it is ingested and later executed.
|
|
10
|
-
import { computed } from 'vue'
|
|
11
|
-
import type { InitiativeItem } from '~/types/domain'
|
|
10
|
+
import { computed, reactive, ref } from 'vue'
|
|
11
|
+
import type { InitiativeFollowUp, InitiativeItem } from '~/types/domain'
|
|
12
12
|
import {
|
|
13
|
+
INITIATIVE_FOLLOWUP_STATUS_CHIPS,
|
|
14
|
+
INITIATIVE_FOLLOWUP_STATUS_LABEL_KEYS,
|
|
13
15
|
INITIATIVE_ITEM_STATUS_CHIPS,
|
|
14
16
|
INITIATIVE_ITEM_STATUS_LABEL_KEYS,
|
|
15
17
|
INITIATIVE_STATUS_LABEL_KEYS,
|
|
@@ -19,6 +21,7 @@ import {
|
|
|
19
21
|
const board = useBoardStore()
|
|
20
22
|
const initiatives = useInitiativesStore()
|
|
21
23
|
const { t } = useI18n()
|
|
24
|
+
const toast = useToast()
|
|
22
25
|
|
|
23
26
|
const { open, blockId, close } = useResultView('initiative-tracker', {
|
|
24
27
|
onOpen: (id) => void initiatives.load(id),
|
|
@@ -52,6 +55,93 @@ function ruleAxes(rule: { minComplexity?: number; minRisk?: number; minImpact?:
|
|
|
52
55
|
].filter((a): a is string => a !== null)
|
|
53
56
|
return axes.length ? axes.join(' · ') : t('initiative.tracker.axisNever')
|
|
54
57
|
}
|
|
58
|
+
|
|
59
|
+
// ---- Curation (slice 4): only meaningful while the initiative is still executing ----
|
|
60
|
+
const editable = computed(() => initiative.value?.status === 'executing')
|
|
61
|
+
|
|
62
|
+
/** Report a failed curation call as a toast (a stale-rev CAS conflict, an illegal edit, …). */
|
|
63
|
+
function reportError(error: unknown) {
|
|
64
|
+
const message = error instanceof Error ? error.message : t('initiative.curation.failed')
|
|
65
|
+
toast.add({ title: t('initiative.curation.failed'), description: message, color: 'error' })
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Follow-up promotion: an inline per-follow-up form (phase + optional title override).
|
|
69
|
+
const promotingId = ref<string | null>(null)
|
|
70
|
+
const promoteForm = reactive<{ phaseId: string; title: string }>({ phaseId: '', title: '' })
|
|
71
|
+
|
|
72
|
+
function startPromote(followUp: InitiativeFollowUp) {
|
|
73
|
+
const sourcePhase = (initiative.value?.items ?? []).find(
|
|
74
|
+
(i) => i.id === followUp.sourceItemId,
|
|
75
|
+
)?.phaseId
|
|
76
|
+
promoteForm.phaseId = sourcePhase ?? phases.value[0]?.id ?? ''
|
|
77
|
+
promoteForm.title = followUp.title
|
|
78
|
+
promotingId.value = followUp.id
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async function submitPromote(followUp: InitiativeFollowUp) {
|
|
82
|
+
if (!initiative.value || !promoteForm.phaseId) return
|
|
83
|
+
try {
|
|
84
|
+
await initiatives.promoteFollowUp(initiative.value.id, followUp.id, {
|
|
85
|
+
phaseId: promoteForm.phaseId,
|
|
86
|
+
...(promoteForm.title.trim() && promoteForm.title.trim() !== followUp.title
|
|
87
|
+
? { title: promoteForm.title.trim() }
|
|
88
|
+
: {}),
|
|
89
|
+
})
|
|
90
|
+
promotingId.value = null
|
|
91
|
+
} catch (error) {
|
|
92
|
+
reportError(error)
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async function dismissFollowUp(followUp: InitiativeFollowUp) {
|
|
97
|
+
if (!initiative.value) return
|
|
98
|
+
try {
|
|
99
|
+
await initiatives.dismissFollowUp(initiative.value.id, followUp.id)
|
|
100
|
+
} catch (error) {
|
|
101
|
+
reportError(error)
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Item status control: retry a blocked item, or skip a pending/blocked one.
|
|
106
|
+
async function itemAction(item: InitiativeItem, action: 'retry' | 'skip') {
|
|
107
|
+
if (!initiative.value) return
|
|
108
|
+
try {
|
|
109
|
+
await initiatives.updateItem(initiative.value.id, item.id, { action })
|
|
110
|
+
} catch (error) {
|
|
111
|
+
reportError(error)
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Policy editing: retune the two scalar knobs (concurrency + default pipeline) while preserving
|
|
116
|
+
// the planner-authored rules. A full rule editor stays out of scope — re-plan to reshape rules.
|
|
117
|
+
const editingPolicy = ref(false)
|
|
118
|
+
const policyForm = reactive<{ maxConcurrent: number; defaultPipelineId: string }>({
|
|
119
|
+
maxConcurrent: 1,
|
|
120
|
+
defaultPipelineId: '',
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
function startEditPolicy() {
|
|
124
|
+
const policy = initiative.value?.policy
|
|
125
|
+
if (!policy) return
|
|
126
|
+
policyForm.maxConcurrent = policy.maxConcurrent
|
|
127
|
+
policyForm.defaultPipelineId = policy.defaultPipelineId
|
|
128
|
+
editingPolicy.value = true
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
async function savePolicy() {
|
|
132
|
+
const policy = initiative.value?.policy
|
|
133
|
+
if (!initiative.value || !policy) return
|
|
134
|
+
try {
|
|
135
|
+
await initiatives.updatePolicy(initiative.value.id, {
|
|
136
|
+
...policy,
|
|
137
|
+
maxConcurrent: policyForm.maxConcurrent,
|
|
138
|
+
defaultPipelineId: policyForm.defaultPipelineId.trim() || policy.defaultPipelineId,
|
|
139
|
+
})
|
|
140
|
+
editingPolicy.value = false
|
|
141
|
+
} catch (error) {
|
|
142
|
+
reportError(error)
|
|
143
|
+
}
|
|
144
|
+
}
|
|
55
145
|
</script>
|
|
56
146
|
|
|
57
147
|
<template>
|
|
@@ -193,10 +283,34 @@ function ruleAxes(rule: { minComplexity?: number; minRisk?: number; minImpact?:
|
|
|
193
283
|
<div v-if="item.note" class="mt-0.5 text-[10px] text-amber-300/80">
|
|
194
284
|
{{ item.note }}
|
|
195
285
|
</div>
|
|
286
|
+
<div
|
|
287
|
+
v-if="
|
|
288
|
+
editable && (item.status === 'blocked' || item.status === 'pending')
|
|
289
|
+
"
|
|
290
|
+
class="mt-1 flex gap-1.5"
|
|
291
|
+
>
|
|
292
|
+
<button
|
|
293
|
+
v-if="item.status === 'blocked'"
|
|
294
|
+
class="rounded border border-slate-700 px-1.5 py-0.5 text-[10px] text-slate-300 hover:bg-slate-800 disabled:opacity-50"
|
|
295
|
+
:disabled="initiatives.curating"
|
|
296
|
+
:data-testid="`initiative-item-retry-${item.id}`"
|
|
297
|
+
@click="itemAction(item, 'retry')"
|
|
298
|
+
>
|
|
299
|
+
{{ t('initiative.curation.retry') }}
|
|
300
|
+
</button>
|
|
301
|
+
<button
|
|
302
|
+
class="rounded border border-slate-700 px-1.5 py-0.5 text-[10px] text-slate-300 hover:bg-slate-800 disabled:opacity-50"
|
|
303
|
+
:disabled="initiatives.curating"
|
|
304
|
+
:data-testid="`initiative-item-skip-${item.id}`"
|
|
305
|
+
@click="itemAction(item, 'skip')"
|
|
306
|
+
>
|
|
307
|
+
{{ t('initiative.curation.skip') }}
|
|
308
|
+
</button>
|
|
309
|
+
</div>
|
|
196
310
|
</td>
|
|
197
311
|
<td class="px-3 py-2 align-top">
|
|
198
312
|
<UBadge
|
|
199
|
-
:color="INITIATIVE_ITEM_STATUS_CHIPS[item.status]
|
|
313
|
+
:color="INITIATIVE_ITEM_STATUS_CHIPS[item.status]"
|
|
200
314
|
variant="subtle"
|
|
201
315
|
size="sm"
|
|
202
316
|
>
|
|
@@ -225,10 +339,20 @@ function ruleAxes(rule: { minComplexity?: number; minRisk?: number; minImpact?:
|
|
|
225
339
|
|
|
226
340
|
<!-- Execution policy -->
|
|
227
341
|
<section v-if="initiative.policy" class="mb-4">
|
|
228
|
-
<
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
342
|
+
<div class="mb-1 flex items-center gap-2">
|
|
343
|
+
<h3 class="text-[11px] font-semibold uppercase tracking-wide text-slate-500">
|
|
344
|
+
{{ t('initiative.tracker.policy') }}
|
|
345
|
+
</h3>
|
|
346
|
+
<button
|
|
347
|
+
v-if="editable && !editingPolicy"
|
|
348
|
+
class="rounded border border-slate-700 px-1.5 py-0.5 text-[10px] text-slate-300 hover:bg-slate-800"
|
|
349
|
+
data-testid="initiative-policy-edit"
|
|
350
|
+
@click="startEditPolicy"
|
|
351
|
+
>
|
|
352
|
+
{{ t('initiative.curation.edit') }}
|
|
353
|
+
</button>
|
|
354
|
+
</div>
|
|
355
|
+
<ul v-if="!editingPolicy" class="text-[12px] text-slate-300">
|
|
232
356
|
<li>
|
|
233
357
|
{{
|
|
234
358
|
t('initiative.tracker.maxConcurrent', {
|
|
@@ -245,6 +369,45 @@ function ruleAxes(rule: { minComplexity?: number; minRisk?: number; minImpact?:
|
|
|
245
369
|
<code class="text-sky-300">{{ initiative.policy.defaultPipelineId }}</code>
|
|
246
370
|
</li>
|
|
247
371
|
</ul>
|
|
372
|
+
<!-- Edit form: the two scalar knobs; planner-authored rules are preserved. -->
|
|
373
|
+
<div v-else class="flex flex-col gap-2 rounded-lg border border-slate-800 p-3">
|
|
374
|
+
<label class="flex items-center gap-2 text-[12px] text-slate-300">
|
|
375
|
+
<span class="w-40">{{ t('initiative.curation.maxConcurrentField') }}</span>
|
|
376
|
+
<input
|
|
377
|
+
v-model.number="policyForm.maxConcurrent"
|
|
378
|
+
type="number"
|
|
379
|
+
min="1"
|
|
380
|
+
max="20"
|
|
381
|
+
class="w-20 rounded border border-slate-700 bg-slate-950 px-2 py-1 text-slate-200"
|
|
382
|
+
data-testid="initiative-policy-max-concurrent"
|
|
383
|
+
/>
|
|
384
|
+
</label>
|
|
385
|
+
<label class="flex items-center gap-2 text-[12px] text-slate-300">
|
|
386
|
+
<span class="w-40">{{ t('initiative.curation.defaultPipelineField') }}</span>
|
|
387
|
+
<input
|
|
388
|
+
v-model="policyForm.defaultPipelineId"
|
|
389
|
+
type="text"
|
|
390
|
+
class="flex-1 rounded border border-slate-700 bg-slate-950 px-2 py-1 font-mono text-[11px] text-slate-200"
|
|
391
|
+
data-testid="initiative-policy-default-pipeline"
|
|
392
|
+
/>
|
|
393
|
+
</label>
|
|
394
|
+
<div class="flex gap-2">
|
|
395
|
+
<button
|
|
396
|
+
class="rounded bg-indigo-600 px-2 py-1 text-[11px] text-white hover:bg-indigo-500 disabled:opacity-50"
|
|
397
|
+
:disabled="initiatives.curating"
|
|
398
|
+
data-testid="initiative-policy-save"
|
|
399
|
+
@click="savePolicy"
|
|
400
|
+
>
|
|
401
|
+
{{ t('initiative.curation.save') }}
|
|
402
|
+
</button>
|
|
403
|
+
<button
|
|
404
|
+
class="rounded border border-slate-700 px-2 py-1 text-[11px] text-slate-300 hover:bg-slate-800"
|
|
405
|
+
@click="editingPolicy = false"
|
|
406
|
+
>
|
|
407
|
+
{{ t('initiative.curation.cancel') }}
|
|
408
|
+
</button>
|
|
409
|
+
</div>
|
|
410
|
+
</div>
|
|
248
411
|
</section>
|
|
249
412
|
|
|
250
413
|
<!-- Logs -->
|
|
@@ -275,10 +438,85 @@ function ruleAxes(rule: { minComplexity?: number; minRisk?: number; minImpact?:
|
|
|
275
438
|
<h3 class="mb-1 text-[11px] font-semibold uppercase tracking-wide text-slate-500">
|
|
276
439
|
{{ t('initiative.tracker.followUps') }}
|
|
277
440
|
</h3>
|
|
278
|
-
<ul class="
|
|
279
|
-
<li
|
|
280
|
-
|
|
281
|
-
|
|
441
|
+
<ul class="flex flex-col gap-2 text-[13px] text-slate-300">
|
|
442
|
+
<li
|
|
443
|
+
v-for="f in initiative.followUps"
|
|
444
|
+
:key="f.id"
|
|
445
|
+
class="rounded-lg border border-slate-800 p-2.5"
|
|
446
|
+
:data-testid="`initiative-followup-${f.id}`"
|
|
447
|
+
>
|
|
448
|
+
<div class="flex items-start gap-2">
|
|
449
|
+
<div class="min-w-0 flex-1">
|
|
450
|
+
<span class="font-medium">{{ f.title }}</span>
|
|
451
|
+
<span v-if="f.detail" class="text-slate-400"> — {{ f.detail }}</span>
|
|
452
|
+
</div>
|
|
453
|
+
<UBadge
|
|
454
|
+
:color="INITIATIVE_FOLLOWUP_STATUS_CHIPS[f.status]"
|
|
455
|
+
variant="subtle"
|
|
456
|
+
size="sm"
|
|
457
|
+
>
|
|
458
|
+
{{ t(INITIATIVE_FOLLOWUP_STATUS_LABEL_KEYS[f.status]) }}
|
|
459
|
+
</UBadge>
|
|
460
|
+
</div>
|
|
461
|
+
<!-- Triage actions for an open follow-up (only while executing) -->
|
|
462
|
+
<div v-if="editable && f.status === 'open'" class="mt-2">
|
|
463
|
+
<div v-if="promotingId === f.id" class="flex flex-col gap-2">
|
|
464
|
+
<label class="flex items-center gap-2 text-[12px]">
|
|
465
|
+
<span class="text-slate-400">{{
|
|
466
|
+
t('initiative.curation.phaseField')
|
|
467
|
+
}}</span>
|
|
468
|
+
<select
|
|
469
|
+
v-model="promoteForm.phaseId"
|
|
470
|
+
class="flex-1 rounded border border-slate-700 bg-slate-950 px-2 py-1 text-slate-200"
|
|
471
|
+
data-testid="initiative-promote-phase"
|
|
472
|
+
>
|
|
473
|
+
<option v-for="p in phases" :key="p.id" :value="p.id">
|
|
474
|
+
{{ p.title }}
|
|
475
|
+
</option>
|
|
476
|
+
</select>
|
|
477
|
+
</label>
|
|
478
|
+
<input
|
|
479
|
+
v-model="promoteForm.title"
|
|
480
|
+
type="text"
|
|
481
|
+
class="rounded border border-slate-700 bg-slate-950 px-2 py-1 text-[12px] text-slate-200"
|
|
482
|
+
:placeholder="t('initiative.curation.itemTitlePlaceholder')"
|
|
483
|
+
data-testid="initiative-promote-title"
|
|
484
|
+
/>
|
|
485
|
+
<div class="flex gap-2">
|
|
486
|
+
<button
|
|
487
|
+
class="rounded bg-indigo-600 px-2 py-1 text-[11px] text-white hover:bg-indigo-500 disabled:opacity-50"
|
|
488
|
+
:disabled="initiatives.curating || !promoteForm.phaseId"
|
|
489
|
+
data-testid="initiative-promote-submit"
|
|
490
|
+
@click="submitPromote(f)"
|
|
491
|
+
>
|
|
492
|
+
{{ t('initiative.curation.promoteConfirm') }}
|
|
493
|
+
</button>
|
|
494
|
+
<button
|
|
495
|
+
class="rounded border border-slate-700 px-2 py-1 text-[11px] text-slate-300 hover:bg-slate-800"
|
|
496
|
+
@click="promotingId = null"
|
|
497
|
+
>
|
|
498
|
+
{{ t('initiative.curation.cancel') }}
|
|
499
|
+
</button>
|
|
500
|
+
</div>
|
|
501
|
+
</div>
|
|
502
|
+
<div v-else class="flex gap-1.5">
|
|
503
|
+
<button
|
|
504
|
+
class="rounded border border-slate-700 px-1.5 py-0.5 text-[10px] text-slate-300 hover:bg-slate-800"
|
|
505
|
+
data-testid="initiative-followup-promote"
|
|
506
|
+
@click="startPromote(f)"
|
|
507
|
+
>
|
|
508
|
+
{{ t('initiative.curation.promote') }}
|
|
509
|
+
</button>
|
|
510
|
+
<button
|
|
511
|
+
class="rounded border border-slate-700 px-1.5 py-0.5 text-[10px] text-slate-300 hover:bg-slate-800 disabled:opacity-50"
|
|
512
|
+
:disabled="initiatives.curating"
|
|
513
|
+
data-testid="initiative-followup-dismiss"
|
|
514
|
+
@click="dismissFollowUp(f)"
|
|
515
|
+
>
|
|
516
|
+
{{ t('initiative.curation.dismiss') }}
|
|
517
|
+
</button>
|
|
518
|
+
</div>
|
|
519
|
+
</div>
|
|
282
520
|
</li>
|
|
283
521
|
</ul>
|
|
284
522
|
</section>
|
|
@@ -66,6 +66,7 @@ const REASON_KEYS: Record<MergeDecision['reason'], string> = {
|
|
|
66
66
|
no_rationale: 'panels.mergerResult.reason.no_rationale',
|
|
67
67
|
no_assessment: 'panels.mergerResult.reason.no_assessment',
|
|
68
68
|
merge_failed: 'panels.mergerResult.reason.merge_failed',
|
|
69
|
+
merge_partial: 'panels.mergerResult.reason.merge_partial',
|
|
69
70
|
}
|
|
70
71
|
const OUTCOME_KEYS: Record<MergeDecision['outcome'], string> = {
|
|
71
72
|
auto_merged: 'panels.mergerResult.outcome.auto_merged',
|
|
@@ -3,12 +3,21 @@ import {
|
|
|
3
3
|
cancelInitiativeContract,
|
|
4
4
|
continueInitiativePlanningContract,
|
|
5
5
|
createInitiativeContract,
|
|
6
|
+
dismissInitiativeFollowUpContract,
|
|
6
7
|
getInitiativeByBlockContract,
|
|
7
8
|
getInitiativeContract,
|
|
8
9
|
listInitiativesContract,
|
|
9
10
|
pauseInitiativeContract,
|
|
10
11
|
proceedInitiativePlanningContract,
|
|
12
|
+
promoteInitiativeFollowUpContract,
|
|
11
13
|
resumeInitiativeContract,
|
|
14
|
+
updateInitiativeItemContract,
|
|
15
|
+
updateInitiativePolicyContract,
|
|
16
|
+
} from '@cat-factory/contracts'
|
|
17
|
+
import type {
|
|
18
|
+
InitiativeExecutionPolicy,
|
|
19
|
+
PromoteInitiativeFollowUpInput,
|
|
20
|
+
UpdateInitiativeItemInput,
|
|
12
21
|
} from '@cat-factory/contracts'
|
|
13
22
|
import type { ApiContext } from './context'
|
|
14
23
|
|
|
@@ -66,5 +75,47 @@ export function initiativeApi({ send, ws }: ApiContext) {
|
|
|
66
75
|
|
|
67
76
|
cancelInitiative: (workspaceId: string, blockId: string) =>
|
|
68
77
|
send(cancelInitiativeContract, { pathPrefix: ws(workspaceId), pathParams: { blockId } }),
|
|
78
|
+
|
|
79
|
+
// Follow-up triage + item/policy editing (slice 4): keyed by initiative id.
|
|
80
|
+
promoteInitiativeFollowUp: (
|
|
81
|
+
workspaceId: string,
|
|
82
|
+
initiativeId: string,
|
|
83
|
+
followUpId: string,
|
|
84
|
+
body: PromoteInitiativeFollowUpInput,
|
|
85
|
+
) =>
|
|
86
|
+
send(promoteInitiativeFollowUpContract, {
|
|
87
|
+
pathPrefix: ws(workspaceId),
|
|
88
|
+
pathParams: { initiativeId, followUpId },
|
|
89
|
+
body,
|
|
90
|
+
}),
|
|
91
|
+
|
|
92
|
+
dismissInitiativeFollowUp: (workspaceId: string, initiativeId: string, followUpId: string) =>
|
|
93
|
+
send(dismissInitiativeFollowUpContract, {
|
|
94
|
+
pathPrefix: ws(workspaceId),
|
|
95
|
+
pathParams: { initiativeId, followUpId },
|
|
96
|
+
}),
|
|
97
|
+
|
|
98
|
+
updateInitiativeItem: (
|
|
99
|
+
workspaceId: string,
|
|
100
|
+
initiativeId: string,
|
|
101
|
+
itemId: string,
|
|
102
|
+
body: UpdateInitiativeItemInput,
|
|
103
|
+
) =>
|
|
104
|
+
send(updateInitiativeItemContract, {
|
|
105
|
+
pathPrefix: ws(workspaceId),
|
|
106
|
+
pathParams: { initiativeId, itemId },
|
|
107
|
+
body,
|
|
108
|
+
}),
|
|
109
|
+
|
|
110
|
+
updateInitiativePolicy: (
|
|
111
|
+
workspaceId: string,
|
|
112
|
+
initiativeId: string,
|
|
113
|
+
body: InitiativeExecutionPolicy,
|
|
114
|
+
) =>
|
|
115
|
+
send(updateInitiativePolicyContract, {
|
|
116
|
+
pathPrefix: ws(workspaceId),
|
|
117
|
+
pathParams: { initiativeId },
|
|
118
|
+
body,
|
|
119
|
+
}),
|
|
69
120
|
}
|
|
70
121
|
}
|
package/app/stores/initiative.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { defineStore } from 'pinia'
|
|
2
2
|
import { computed, ref } from 'vue'
|
|
3
|
-
import type {
|
|
3
|
+
import type {
|
|
4
|
+
Initiative,
|
|
5
|
+
InitiativeExecutionPolicy,
|
|
6
|
+
PromoteInitiativeFollowUpInput,
|
|
7
|
+
UpdateInitiativeItemInput,
|
|
8
|
+
} from '~/types/domain'
|
|
4
9
|
import { useWorkspaceStore } from '~/stores/workspace'
|
|
5
10
|
import { useBoardStore } from '~/stores/board'
|
|
6
11
|
|
|
@@ -154,6 +159,77 @@ export const useInitiativesStore = defineStore('initiatives', () => {
|
|
|
154
159
|
}
|
|
155
160
|
}
|
|
156
161
|
|
|
162
|
+
/** True while a curation action (promote/dismiss/edit item/edit policy) is in flight. */
|
|
163
|
+
const curating = ref(false)
|
|
164
|
+
|
|
165
|
+
async function curate<T>(fn: () => Promise<T>): Promise<T> {
|
|
166
|
+
if (!workspace.workspaceId) throw new Error('No active workspace')
|
|
167
|
+
curating.value = true
|
|
168
|
+
try {
|
|
169
|
+
return await fn()
|
|
170
|
+
} finally {
|
|
171
|
+
curating.value = false
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/** Promote an `open` harvested follow-up into a new pending tracker item. */
|
|
176
|
+
async function promoteFollowUp(
|
|
177
|
+
initiativeId: string,
|
|
178
|
+
followUpId: string,
|
|
179
|
+
input: PromoteInitiativeFollowUpInput,
|
|
180
|
+
) {
|
|
181
|
+
return curate(async () => {
|
|
182
|
+
const updated = await api.promoteInitiativeFollowUp(
|
|
183
|
+
workspace.workspaceId!,
|
|
184
|
+
initiativeId,
|
|
185
|
+
followUpId,
|
|
186
|
+
input,
|
|
187
|
+
)
|
|
188
|
+
upsert(updated)
|
|
189
|
+
return updated
|
|
190
|
+
})
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/** Dismiss a harvested follow-up. */
|
|
194
|
+
async function dismissFollowUp(initiativeId: string, followUpId: string) {
|
|
195
|
+
return curate(async () => {
|
|
196
|
+
const updated = await api.dismissInitiativeFollowUp(
|
|
197
|
+
workspace.workspaceId!,
|
|
198
|
+
initiativeId,
|
|
199
|
+
followUpId,
|
|
200
|
+
)
|
|
201
|
+
upsert(updated)
|
|
202
|
+
return updated
|
|
203
|
+
})
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/** Edit one tracker item and/or drive its status (retry a blocked item / skip it). */
|
|
207
|
+
async function updateItem(
|
|
208
|
+
initiativeId: string,
|
|
209
|
+
itemId: string,
|
|
210
|
+
input: UpdateInitiativeItemInput,
|
|
211
|
+
) {
|
|
212
|
+
return curate(async () => {
|
|
213
|
+
const updated = await api.updateInitiativeItem(
|
|
214
|
+
workspace.workspaceId!,
|
|
215
|
+
initiativeId,
|
|
216
|
+
itemId,
|
|
217
|
+
input,
|
|
218
|
+
)
|
|
219
|
+
upsert(updated)
|
|
220
|
+
return updated
|
|
221
|
+
})
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/** Replace the execution policy (concurrency + pipeline rules). */
|
|
225
|
+
async function updatePolicy(initiativeId: string, policy: InitiativeExecutionPolicy) {
|
|
226
|
+
return curate(async () => {
|
|
227
|
+
const updated = await api.updateInitiativePolicy(workspace.workspaceId!, initiativeId, policy)
|
|
228
|
+
upsert(updated)
|
|
229
|
+
return updated
|
|
230
|
+
})
|
|
231
|
+
}
|
|
232
|
+
|
|
157
233
|
function reset() {
|
|
158
234
|
byBlock.value = {}
|
|
159
235
|
}
|
|
@@ -165,6 +241,7 @@ export const useInitiativesStore = defineStore('initiatives', () => {
|
|
|
165
241
|
creating,
|
|
166
242
|
resuming,
|
|
167
243
|
controlling,
|
|
244
|
+
curating,
|
|
168
245
|
forBlock,
|
|
169
246
|
hydrate,
|
|
170
247
|
upsert,
|
|
@@ -174,6 +251,10 @@ export const useInitiativesStore = defineStore('initiatives', () => {
|
|
|
174
251
|
continuePlanning,
|
|
175
252
|
proceedPlanning,
|
|
176
253
|
control,
|
|
254
|
+
promoteFollowUp,
|
|
255
|
+
dismissFollowUp,
|
|
256
|
+
updateItem,
|
|
257
|
+
updatePolicy,
|
|
177
258
|
reset,
|
|
178
259
|
}
|
|
179
260
|
})
|
package/app/types/initiative.ts
CHANGED
package/app/types/recurring.ts
CHANGED
package/app/utils/catalog.ts
CHANGED
|
@@ -51,16 +51,18 @@ export const AGENT_ARCHETYPES: AgentArchetype[] = [
|
|
|
51
51
|
resultView: 'clarity-review',
|
|
52
52
|
},
|
|
53
53
|
{
|
|
54
|
-
// A read-only
|
|
55
|
-
//
|
|
56
|
-
//
|
|
54
|
+
// A read-only, structured `container-explore` agent, so it's a first-class palette block a
|
|
55
|
+
// user can add to any pipeline — not just the `pl_bugfix` preset where it leads. Its
|
|
56
|
+
// structured triage opens in the shared generic viewer; the clarity gate consumes its
|
|
57
|
+
// `clarity`/`questions` server-side.
|
|
57
58
|
kind: 'bug-investigator',
|
|
58
59
|
label: 'Bug Investigator',
|
|
59
60
|
icon: 'i-lucide-search-code',
|
|
60
61
|
color: '#38bdf8',
|
|
61
62
|
category: 'review',
|
|
62
63
|
description:
|
|
63
|
-
'Read-only codebase investigation that traces the bug to its root cause and
|
|
64
|
+
'Read-only, multi-repo codebase investigation that traces the bug to its root cause and decides whether the report is fixable as-is or needs the reporter to clarify (no code changes).',
|
|
65
|
+
resultView: 'generic-structured',
|
|
64
66
|
},
|
|
65
67
|
{
|
|
66
68
|
kind: 'task-estimator',
|
package/app/utils/initiative.ts
CHANGED
|
@@ -1,10 +1,19 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
InitiativeFollowUp,
|
|
3
|
+
InitiativeItem,
|
|
4
|
+
InitiativeItemStatus,
|
|
5
|
+
InitiativeStatus,
|
|
6
|
+
} from '~/types/domain'
|
|
2
7
|
|
|
3
8
|
// Shared initiative presentation vocabulary, so the board card, the inspector body and
|
|
4
9
|
// the tracker window render statuses/progress from ONE source. The exhaustive
|
|
5
|
-
// `Record<Enum,
|
|
10
|
+
// `Record<Enum, …>` maps keep the tier-2 typecheck guard live (a new status without
|
|
6
11
|
// a label/chip fails the build) without triplicating it across the components.
|
|
7
12
|
|
|
13
|
+
/** Nuxt UI badge/chip colour names — mirrors `UBadge`'s `color` prop union, so a chip map
|
|
14
|
+
* types its values against it and the `:color` binding needs no cast. */
|
|
15
|
+
type BadgeColor = 'error' | 'info' | 'primary' | 'secondary' | 'success' | 'warning' | 'neutral'
|
|
16
|
+
|
|
8
17
|
/** Initiative lifecycle status → i18n label key. */
|
|
9
18
|
export const INITIATIVE_STATUS_LABEL_KEYS: Record<InitiativeStatus, string> = {
|
|
10
19
|
planning: 'initiative.status.planning',
|
|
@@ -16,7 +25,7 @@ export const INITIATIVE_STATUS_LABEL_KEYS: Record<InitiativeStatus, string> = {
|
|
|
16
25
|
}
|
|
17
26
|
|
|
18
27
|
/** Initiative lifecycle status → Nuxt UI badge colour. */
|
|
19
|
-
export const INITIATIVE_STATUS_CHIPS: Record<InitiativeStatus,
|
|
28
|
+
export const INITIATIVE_STATUS_CHIPS: Record<InitiativeStatus, BadgeColor> = {
|
|
20
29
|
planning: 'neutral',
|
|
21
30
|
awaiting_approval: 'warning',
|
|
22
31
|
executing: 'info',
|
|
@@ -36,7 +45,7 @@ export const INITIATIVE_ITEM_STATUS_LABEL_KEYS: Record<InitiativeItemStatus, str
|
|
|
36
45
|
}
|
|
37
46
|
|
|
38
47
|
/** Tracker item status → Nuxt UI badge colour. */
|
|
39
|
-
export const INITIATIVE_ITEM_STATUS_CHIPS: Record<InitiativeItemStatus,
|
|
48
|
+
export const INITIATIVE_ITEM_STATUS_CHIPS: Record<InitiativeItemStatus, BadgeColor> = {
|
|
40
49
|
pending: 'neutral',
|
|
41
50
|
in_progress: 'info',
|
|
42
51
|
pr_open: 'warning',
|
|
@@ -45,6 +54,20 @@ export const INITIATIVE_ITEM_STATUS_CHIPS: Record<InitiativeItemStatus, string>
|
|
|
45
54
|
skipped: 'neutral',
|
|
46
55
|
}
|
|
47
56
|
|
|
57
|
+
/** Follow-up triage status → i18n label key. Exhaustive so a new status fails the build. */
|
|
58
|
+
export const INITIATIVE_FOLLOWUP_STATUS_LABEL_KEYS: Record<InitiativeFollowUp['status'], string> = {
|
|
59
|
+
open: 'initiative.followUpStatus.open',
|
|
60
|
+
promoted: 'initiative.followUpStatus.promoted',
|
|
61
|
+
dismissed: 'initiative.followUpStatus.dismissed',
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Follow-up triage status → Nuxt UI badge colour. */
|
|
65
|
+
export const INITIATIVE_FOLLOWUP_STATUS_CHIPS: Record<InitiativeFollowUp['status'], BadgeColor> = {
|
|
66
|
+
open: 'warning',
|
|
67
|
+
promoted: 'success',
|
|
68
|
+
dismissed: 'neutral',
|
|
69
|
+
}
|
|
70
|
+
|
|
48
71
|
/** Item statuses that count as settled — mirrors the backend terminal-status set. */
|
|
49
72
|
const SETTLED: ReadonlySet<InitiativeItemStatus> = new Set(['done', 'skipped'])
|
|
50
73
|
|
package/i18n/locales/en.json
CHANGED
|
@@ -219,7 +219,17 @@
|
|
|
219
219
|
"submit": "Add recurring pipeline",
|
|
220
220
|
"addFailedTitle": "Could not add recurring pipeline",
|
|
221
221
|
"onDemand": "On-demand (manual only)",
|
|
222
|
-
"onDemandHint": "Runs only when you trigger it, with no schedule. Because you are present each time, its task may use an individual-usage subscription model."
|
|
222
|
+
"onDemandHint": "Runs only when you trigger it, with no schedule. Because you are present each time, its task may use an individual-usage subscription model.",
|
|
223
|
+
"intake": "Issue intake",
|
|
224
|
+
"intakeHint": "Each run picks one matching open issue from the tracker and works it end to end.",
|
|
225
|
+
"intakeNoSources": "Connect a task source first to pull issues from it.",
|
|
226
|
+
"intakeGithubRepo": "Repository",
|
|
227
|
+
"intakeTitleFragment": "Title contains",
|
|
228
|
+
"intakeTitleFragmentPlaceholder": "e.g. crash",
|
|
229
|
+
"intakeLabels": "Labels",
|
|
230
|
+
"intakeLabelsPlaceholder": "comma-separated",
|
|
231
|
+
"intakeIssueType": "Issue type",
|
|
232
|
+
"intakeInProgressLabel": "In-progress label"
|
|
223
233
|
},
|
|
224
234
|
"failure": {
|
|
225
235
|
"containerFailedToStart": "Container failed to start",
|
|
@@ -854,7 +864,8 @@
|
|
|
854
864
|
"auto_merge_disabled": "The {preset} preset sends every PR to a human, so this one is waiting for review.",
|
|
855
865
|
"no_rationale": "The merger scored the PR but gave no rationale, so the verdict could not be trusted to auto-merge; the PR is waiting for a human to merge.",
|
|
856
866
|
"no_assessment": "The merger did not return a parseable assessment, so the PR is waiting for a human to merge.",
|
|
857
|
-
"merge_failed": "The scores were within the {preset} thresholds, but the automatic merge could not complete (for example branch protection or a conflict), so the PR is waiting for a human to merge."
|
|
867
|
+
"merge_failed": "The scores were within the {preset} thresholds, but the automatic merge could not complete (for example branch protection or a conflict), so the PR is waiting for a human to merge.",
|
|
868
|
+
"merge_partial": "Some of the task's pull requests merged, but a later one could not, so the change is waiting for a human to finish or revert the multi-repo merge."
|
|
858
869
|
},
|
|
859
870
|
"scores": "Scores",
|
|
860
871
|
"axis": {
|
|
@@ -4166,6 +4177,26 @@
|
|
|
4166
4177
|
"hint": "Continue lets the planner ask follow-ups; Proceed plans with the answers so far.",
|
|
4167
4178
|
"proceed": "Proceed to plan",
|
|
4168
4179
|
"continue": "Continue"
|
|
4180
|
+
},
|
|
4181
|
+
"followUpStatus": {
|
|
4182
|
+
"open": "Open",
|
|
4183
|
+
"promoted": "Promoted",
|
|
4184
|
+
"dismissed": "Dismissed"
|
|
4185
|
+
},
|
|
4186
|
+
"curation": {
|
|
4187
|
+
"promote": "Promote to item",
|
|
4188
|
+
"promoteConfirm": "Create item",
|
|
4189
|
+
"dismiss": "Dismiss",
|
|
4190
|
+
"retry": "Retry",
|
|
4191
|
+
"skip": "Skip",
|
|
4192
|
+
"edit": "Edit",
|
|
4193
|
+
"save": "Save",
|
|
4194
|
+
"cancel": "Cancel",
|
|
4195
|
+
"phaseField": "Phase",
|
|
4196
|
+
"itemTitlePlaceholder": "Item title (defaults to the follow-up's)",
|
|
4197
|
+
"maxConcurrentField": "Max concurrent tasks",
|
|
4198
|
+
"defaultPipelineField": "Default pipeline",
|
|
4199
|
+
"failed": "Could not update the initiative"
|
|
4169
4200
|
}
|
|
4170
4201
|
}
|
|
4171
4202
|
}
|
package/i18n/locales/es.json
CHANGED
|
@@ -198,7 +198,17 @@
|
|
|
198
198
|
"submit": "Añadir pipeline recurrente",
|
|
199
199
|
"addFailedTitle": "No se pudo añadir la pipeline recurrente",
|
|
200
200
|
"onDemand": "Bajo demanda (solo manual)",
|
|
201
|
-
"onDemandHint": "Se ejecuta solo cuando lo activas, sin programación. Como estás presente cada vez, su tarea puede usar un modelo de suscripción de uso individual."
|
|
201
|
+
"onDemandHint": "Se ejecuta solo cuando lo activas, sin programación. Como estás presente cada vez, su tarea puede usar un modelo de suscripción de uso individual.",
|
|
202
|
+
"intake": "Admisión de incidencias",
|
|
203
|
+
"intakeHint": "Cada ejecución toma una incidencia abierta que coincide del rastreador y la resuelve de principio a fin.",
|
|
204
|
+
"intakeNoSources": "Primero conecta una fuente de tareas para extraer incidencias de ella.",
|
|
205
|
+
"intakeGithubRepo": "Repositorio",
|
|
206
|
+
"intakeTitleFragment": "El título contiene",
|
|
207
|
+
"intakeTitleFragmentPlaceholder": "p. ej. crash",
|
|
208
|
+
"intakeLabels": "Etiquetas",
|
|
209
|
+
"intakeLabelsPlaceholder": "separadas por comas",
|
|
210
|
+
"intakeIssueType": "Tipo de incidencia",
|
|
211
|
+
"intakeInProgressLabel": "Etiqueta de en progreso"
|
|
202
212
|
},
|
|
203
213
|
"failure": {
|
|
204
214
|
"containerFailedToStart": "El contenedor no pudo iniciarse",
|
|
@@ -811,7 +821,8 @@
|
|
|
811
821
|
"auto_merge_disabled": "El preajuste {preset} envía todos los PR a una persona, así que este espera revisión.",
|
|
812
822
|
"no_rationale": "El fusionador puntuó el PR pero no dio ninguna justificación, así que no se pudo confiar en el veredicto para fusionar automáticamente; el PR espera a que una persona lo fusione.",
|
|
813
823
|
"no_assessment": "El fusionador no devolvió una evaluación analizable, por lo que el PR espera a que una persona lo fusione.",
|
|
814
|
-
"merge_failed": "Las puntuaciones estaban dentro de los umbrales de {preset}, pero la fusión automática no pudo completarse (por ejemplo, protección de rama o un conflicto), por lo que el PR espera a que una persona lo fusione."
|
|
824
|
+
"merge_failed": "Las puntuaciones estaban dentro de los umbrales de {preset}, pero la fusión automática no pudo completarse (por ejemplo, protección de rama o un conflicto), por lo que el PR espera a que una persona lo fusione.",
|
|
825
|
+
"merge_partial": "Algunas de las solicitudes de incorporación de la tarea se fusionaron, pero una posterior no pudo, por lo que el cambio espera a que una persona termine o revierta la fusión multirrepositorio."
|
|
815
826
|
},
|
|
816
827
|
"scores": "Puntuaciones",
|
|
817
828
|
"axis": {
|
|
@@ -4048,6 +4059,26 @@
|
|
|
4048
4059
|
"hint": "Continuar permite al planificador hacer mas preguntas; Proceder planifica con las respuestas actuales.",
|
|
4049
4060
|
"proceed": "Proceder a planificar",
|
|
4050
4061
|
"continue": "Continuar"
|
|
4062
|
+
},
|
|
4063
|
+
"followUpStatus": {
|
|
4064
|
+
"open": "Abierto",
|
|
4065
|
+
"promoted": "Promovido",
|
|
4066
|
+
"dismissed": "Descartado"
|
|
4067
|
+
},
|
|
4068
|
+
"curation": {
|
|
4069
|
+
"promote": "Promover a elemento",
|
|
4070
|
+
"promoteConfirm": "Crear elemento",
|
|
4071
|
+
"dismiss": "Descartar",
|
|
4072
|
+
"retry": "Reintentar",
|
|
4073
|
+
"skip": "Omitir",
|
|
4074
|
+
"edit": "Editar",
|
|
4075
|
+
"save": "Guardar",
|
|
4076
|
+
"cancel": "Cancelar",
|
|
4077
|
+
"phaseField": "Fase",
|
|
4078
|
+
"itemTitlePlaceholder": "Titulo del elemento (por defecto el del seguimiento)",
|
|
4079
|
+
"maxConcurrentField": "Tareas concurrentes maximas",
|
|
4080
|
+
"defaultPipelineField": "Pipeline por defecto",
|
|
4081
|
+
"failed": "No se pudo actualizar la iniciativa"
|
|
4051
4082
|
}
|
|
4052
4083
|
}
|
|
4053
4084
|
}
|
package/i18n/locales/fr.json
CHANGED
|
@@ -198,7 +198,17 @@
|
|
|
198
198
|
"submit": "Ajouter la pipeline récurrente",
|
|
199
199
|
"addFailedTitle": "Impossible d’ajouter la pipeline récurrente",
|
|
200
200
|
"onDemand": "À la demande (manuel uniquement)",
|
|
201
|
-
"onDemandHint": "Ne s'exécute que lorsque vous le déclenchez, sans planification. Comme vous êtes présent à chaque fois, sa tâche peut utiliser un modèle d'abonnement à usage individuel."
|
|
201
|
+
"onDemandHint": "Ne s'exécute que lorsque vous le déclenchez, sans planification. Comme vous êtes présent à chaque fois, sa tâche peut utiliser un modèle d'abonnement à usage individuel.",
|
|
202
|
+
"intake": "Prise en charge des tickets",
|
|
203
|
+
"intakeHint": "Chaque exécution sélectionne un ticket ouvert correspondant dans le suivi et le traite de bout en bout.",
|
|
204
|
+
"intakeNoSources": "Connectez d'abord une source de tâches pour en extraire des tickets.",
|
|
205
|
+
"intakeGithubRepo": "Dépôt",
|
|
206
|
+
"intakeTitleFragment": "Le titre contient",
|
|
207
|
+
"intakeTitleFragmentPlaceholder": "ex. crash",
|
|
208
|
+
"intakeLabels": "Étiquettes",
|
|
209
|
+
"intakeLabelsPlaceholder": "séparées par des virgules",
|
|
210
|
+
"intakeIssueType": "Type de ticket",
|
|
211
|
+
"intakeInProgressLabel": "Étiquette en cours"
|
|
202
212
|
},
|
|
203
213
|
"failure": {
|
|
204
214
|
"containerFailedToStart": "Le conteneur n’a pas pu démarrer",
|
|
@@ -811,7 +821,8 @@
|
|
|
811
821
|
"auto_merge_disabled": "Le préréglage {preset} envoie chaque PR à une personne ; celle-ci attend donc une revue.",
|
|
812
822
|
"no_rationale": "Le fusionneur a évalué la PR mais n'a donné aucune justification, le verdict n'a donc pas pu être approuvé pour une fusion automatique ; la PR attend une fusion par une personne.",
|
|
813
823
|
"no_assessment": "Le fusionneur n'a pas renvoyé d'évaluation exploitable, la PR attend donc une fusion par une personne.",
|
|
814
|
-
"merge_failed": "Les scores étaient dans les seuils de {preset}, mais la fusion automatique n'a pas pu aboutir (par exemple protection de branche ou conflit), la PR attend donc une fusion par une personne."
|
|
824
|
+
"merge_failed": "Les scores étaient dans les seuils de {preset}, mais la fusion automatique n'a pas pu aboutir (par exemple protection de branche ou conflit), la PR attend donc une fusion par une personne.",
|
|
825
|
+
"merge_partial": "Certaines des pull requests de la tâche ont été fusionnées, mais une suivante n'a pas pu l'être, le changement attend donc qu'une personne termine ou annule la fusion multi-dépôt."
|
|
815
826
|
},
|
|
816
827
|
"scores": "Scores",
|
|
817
828
|
"axis": {
|
|
@@ -4048,6 +4059,26 @@
|
|
|
4048
4059
|
"hint": "Continuer permet au planificateur de poser des questions complementaires ; Proceder planifie avec les reponses actuelles.",
|
|
4049
4060
|
"proceed": "Proceder a la planification",
|
|
4050
4061
|
"continue": "Continuer"
|
|
4062
|
+
},
|
|
4063
|
+
"followUpStatus": {
|
|
4064
|
+
"open": "Ouvert",
|
|
4065
|
+
"promoted": "Promu",
|
|
4066
|
+
"dismissed": "Rejete"
|
|
4067
|
+
},
|
|
4068
|
+
"curation": {
|
|
4069
|
+
"promote": "Promouvoir en element",
|
|
4070
|
+
"promoteConfirm": "Creer l'element",
|
|
4071
|
+
"dismiss": "Rejeter",
|
|
4072
|
+
"retry": "Reessayer",
|
|
4073
|
+
"skip": "Ignorer",
|
|
4074
|
+
"edit": "Modifier",
|
|
4075
|
+
"save": "Enregistrer",
|
|
4076
|
+
"cancel": "Annuler",
|
|
4077
|
+
"phaseField": "Phase",
|
|
4078
|
+
"itemTitlePlaceholder": "Titre de l'element (par defaut celui du suivi)",
|
|
4079
|
+
"maxConcurrentField": "Taches simultanees maximales",
|
|
4080
|
+
"defaultPipelineField": "Pipeline par defaut",
|
|
4081
|
+
"failed": "Impossible de mettre a jour l'initiative"
|
|
4051
4082
|
}
|
|
4052
4083
|
}
|
|
4053
4084
|
}
|
package/i18n/locales/he.json
CHANGED
|
@@ -198,7 +198,17 @@
|
|
|
198
198
|
"submit": "הוסף צינור מחזורי",
|
|
199
199
|
"addFailedTitle": "לא ניתן היה להוסיף צינור מחזורי",
|
|
200
200
|
"onDemand": "לפי דרישה (ידני בלבד)",
|
|
201
|
-
"onDemandHint": "רץ רק כשאתה מפעיל אותו, ללא תזמון. מכיוון שאתה נוכח בכל פעם, המשימה יכולה להשתמש במודל מנוי לשימוש אישי."
|
|
201
|
+
"onDemandHint": "רץ רק כשאתה מפעיל אותו, ללא תזמון. מכיוון שאתה נוכח בכל פעם, המשימה יכולה להשתמש במודל מנוי לשימוש אישי.",
|
|
202
|
+
"intake": "קליטת תקלות",
|
|
203
|
+
"intakeHint": "כל הרצה בוחרת תקלה פתוחה תואמת אחת מהמעקב ומטפלת בה מקצה לקצה.",
|
|
204
|
+
"intakeNoSources": "חבר תחילה מקור משימות כדי למשוך ממנו תקלות.",
|
|
205
|
+
"intakeGithubRepo": "מאגר",
|
|
206
|
+
"intakeTitleFragment": "הכותרת מכילה",
|
|
207
|
+
"intakeTitleFragmentPlaceholder": "למשל crash",
|
|
208
|
+
"intakeLabels": "תוויות",
|
|
209
|
+
"intakeLabelsPlaceholder": "מופרדות בפסיקים",
|
|
210
|
+
"intakeIssueType": "סוג תקלה",
|
|
211
|
+
"intakeInProgressLabel": "תווית בתהליך"
|
|
202
212
|
},
|
|
203
213
|
"failure": {
|
|
204
214
|
"containerFailedToStart": "מכל הקונטיינר נכשל בהפעלה",
|
|
@@ -811,7 +821,8 @@
|
|
|
811
821
|
"auto_merge_disabled": "הקדם-הגדרה {preset} שולחת כל PR לאדם, ולכן זה ממתין לבדיקה.",
|
|
812
822
|
"no_rationale": "הממזג נתן ציון ל-PR אך לא סיפק נימוק, ולכן לא ניתן היה לסמוך על ההכרעה למיזוג אוטומטי; ה-PR ממתין למיזוג ידני.",
|
|
813
823
|
"no_assessment": "הממזג לא החזיר הערכה שניתן לפענח, ולכן ה-PR ממתין למיזוג ידני.",
|
|
814
|
-
"merge_failed": "הציונים היו בתוך ספי {preset}, אך המיזוג האוטומטי לא הושלם (למשל הגנת ענף או התנגשות), ולכן ה-PR ממתין למיזוג ידני."
|
|
824
|
+
"merge_failed": "הציונים היו בתוך ספי {preset}, אך המיזוג האוטומטי לא הושלם (למשל הגנת ענף או התנגשות), ולכן ה-PR ממתין למיזוג ידני.",
|
|
825
|
+
"merge_partial": "חלק מבקשות המשיכה של המשימה מוזגו, אך אחת מאוחרת יותר נכשלה, ולכן השינוי ממתין שאדם ישלים או יבטל את המיזוג הרב-מאגרי."
|
|
815
826
|
},
|
|
816
827
|
"scores": "ציונים",
|
|
817
828
|
"axis": {
|
|
@@ -4059,6 +4070,26 @@
|
|
|
4059
4070
|
"hint": "המשך מאפשר למתכנן לשאול שאלות המשך; עבור לתכנון מתכנן עם התשובות עד כה.",
|
|
4060
4071
|
"proceed": "עבור לתכנון",
|
|
4061
4072
|
"continue": "המשך"
|
|
4073
|
+
},
|
|
4074
|
+
"followUpStatus": {
|
|
4075
|
+
"open": "פתוח",
|
|
4076
|
+
"promoted": "קודם",
|
|
4077
|
+
"dismissed": "נדחה"
|
|
4078
|
+
},
|
|
4079
|
+
"curation": {
|
|
4080
|
+
"promote": "קדם לפריט",
|
|
4081
|
+
"promoteConfirm": "צור פריט",
|
|
4082
|
+
"dismiss": "התעלם",
|
|
4083
|
+
"retry": "נסה שוב",
|
|
4084
|
+
"skip": "דלג",
|
|
4085
|
+
"edit": "ערוך",
|
|
4086
|
+
"save": "שמור",
|
|
4087
|
+
"cancel": "בטל",
|
|
4088
|
+
"phaseField": "שלב",
|
|
4089
|
+
"itemTitlePlaceholder": "כותרת הפריט (ברירת מחדל: של המעקב)",
|
|
4090
|
+
"maxConcurrentField": "מקסימום משימות במקביל",
|
|
4091
|
+
"defaultPipelineField": "צינור ברירת מחדל",
|
|
4092
|
+
"failed": "לא ניתן לעדכן את היוזמה"
|
|
4062
4093
|
}
|
|
4063
4094
|
}
|
|
4064
4095
|
}
|
package/i18n/locales/ja.json
CHANGED
|
@@ -198,7 +198,17 @@
|
|
|
198
198
|
"submit": "繰り返しパイプラインを追加",
|
|
199
199
|
"addFailedTitle": "繰り返しパイプラインを追加できませんでした",
|
|
200
200
|
"onDemand": "オンデマンド(手動のみ)",
|
|
201
|
-
"onDemandHint": "スケジュールはなく、手動で実行したときのみ動作します。毎回ユーザーが立ち会うため、タスクは個人利用のサブスクリプションモデルを使用できます。"
|
|
201
|
+
"onDemandHint": "スケジュールはなく、手動で実行したときのみ動作します。毎回ユーザーが立ち会うため、タスクは個人利用のサブスクリプションモデルを使用できます。",
|
|
202
|
+
"intake": "課題の取り込み",
|
|
203
|
+
"intakeHint": "各実行はトラッカーから条件に一致する未解決の課題を1件選び、最後まで対応します。",
|
|
204
|
+
"intakeNoSources": "課題を取り込むには、まずタスクソースを接続してください。",
|
|
205
|
+
"intakeGithubRepo": "リポジトリ",
|
|
206
|
+
"intakeTitleFragment": "タイトルに含む",
|
|
207
|
+
"intakeTitleFragmentPlaceholder": "例: crash",
|
|
208
|
+
"intakeLabels": "ラベル",
|
|
209
|
+
"intakeLabelsPlaceholder": "カンマ区切り",
|
|
210
|
+
"intakeIssueType": "課題タイプ",
|
|
211
|
+
"intakeInProgressLabel": "進行中ラベル"
|
|
202
212
|
},
|
|
203
213
|
"failure": {
|
|
204
214
|
"containerFailedToStart": "コンテナの起動に失敗しました",
|
|
@@ -811,7 +821,8 @@
|
|
|
811
821
|
"auto_merge_disabled": "{preset} プリセットはすべての PR を人に回すため、この PR はレビュー待ちです。",
|
|
812
822
|
"no_rationale": "マージ担当は PR を採点しましたが根拠を示さなかったため、自動マージするには判定を信頼できませんでした。PR は人によるマージを待っています。",
|
|
813
823
|
"no_assessment": "マージ担当が解析可能な評価を返さなかったため、PR は人によるマージを待っています。",
|
|
814
|
-
"merge_failed": "スコアは {preset} のしきい値内でしたが、自動マージを完了できなかった(例: ブランチ保護や競合)ため、PR は人によるマージを待っています。"
|
|
824
|
+
"merge_failed": "スコアは {preset} のしきい値内でしたが、自動マージを完了できなかった(例: ブランチ保護や競合)ため、PR は人によるマージを待っています。",
|
|
825
|
+
"merge_partial": "タスクの一部のプルリクエストはマージされましたが、後続の1つが失敗したため、変更は人が複数リポジトリのマージを完了するか元に戻すのを待っています。"
|
|
815
826
|
},
|
|
816
827
|
"scores": "スコア",
|
|
817
828
|
"axis": {
|
|
@@ -4060,6 +4071,26 @@
|
|
|
4060
4071
|
"hint": "「続行」でプランナーが追加の質問をします。「計画に進む」でこれまでの回答をもとに計画します。",
|
|
4061
4072
|
"proceed": "計画に進む",
|
|
4062
4073
|
"continue": "続行"
|
|
4074
|
+
},
|
|
4075
|
+
"followUpStatus": {
|
|
4076
|
+
"open": "未対応",
|
|
4077
|
+
"promoted": "項目化済み",
|
|
4078
|
+
"dismissed": "却下"
|
|
4079
|
+
},
|
|
4080
|
+
"curation": {
|
|
4081
|
+
"promote": "項目に昇格",
|
|
4082
|
+
"promoteConfirm": "項目を作成",
|
|
4083
|
+
"dismiss": "却下",
|
|
4084
|
+
"retry": "再試行",
|
|
4085
|
+
"skip": "スキップ",
|
|
4086
|
+
"edit": "編集",
|
|
4087
|
+
"save": "保存",
|
|
4088
|
+
"cancel": "キャンセル",
|
|
4089
|
+
"phaseField": "フェーズ",
|
|
4090
|
+
"itemTitlePlaceholder": "項目のタイトル(既定はフォローアップのもの)",
|
|
4091
|
+
"maxConcurrentField": "最大同時実行タスク数",
|
|
4092
|
+
"defaultPipelineField": "既定のパイプライン",
|
|
4093
|
+
"failed": "イニシアチブを更新できませんでした"
|
|
4063
4094
|
}
|
|
4064
4095
|
}
|
|
4065
4096
|
}
|
package/i18n/locales/pl.json
CHANGED
|
@@ -198,7 +198,17 @@
|
|
|
198
198
|
"submit": "Dodaj cykliczny pipeline",
|
|
199
199
|
"addFailedTitle": "Nie udało się dodać cyklicznego pipeline’u",
|
|
200
200
|
"onDemand": "Na żądanie (tylko ręcznie)",
|
|
201
|
-
"onDemandHint": "Uruchamia się tylko po ręcznym wyzwoleniu, bez harmonogramu. Ponieważ za każdym razem jesteś obecny, jego zadanie może korzystać z modelu subskrypcji do użytku indywidualnego."
|
|
201
|
+
"onDemandHint": "Uruchamia się tylko po ręcznym wyzwoleniu, bez harmonogramu. Ponieważ za każdym razem jesteś obecny, jego zadanie może korzystać z modelu subskrypcji do użytku indywidualnego.",
|
|
202
|
+
"intake": "Pobieranie zgłoszeń",
|
|
203
|
+
"intakeHint": "Każde uruchomienie wybiera jedno pasujące otwarte zgłoszenie z trackera i realizuje je od początku do końca.",
|
|
204
|
+
"intakeNoSources": "Najpierw połącz źródło zadań, aby pobierać z niego zgłoszenia.",
|
|
205
|
+
"intakeGithubRepo": "Repozytorium",
|
|
206
|
+
"intakeTitleFragment": "Tytuł zawiera",
|
|
207
|
+
"intakeTitleFragmentPlaceholder": "np. crash",
|
|
208
|
+
"intakeLabels": "Etykiety",
|
|
209
|
+
"intakeLabelsPlaceholder": "oddzielone przecinkami",
|
|
210
|
+
"intakeIssueType": "Typ zgłoszenia",
|
|
211
|
+
"intakeInProgressLabel": "Etykieta w toku"
|
|
202
212
|
},
|
|
203
213
|
"failure": {
|
|
204
214
|
"containerFailedToStart": "Nie udało się uruchomić kontenera",
|
|
@@ -811,7 +821,8 @@
|
|
|
811
821
|
"auto_merge_disabled": "Ustawienie {preset} kieruje każdy PR do człowieka, więc ten czeka na przegląd.",
|
|
812
822
|
"no_rationale": "Scalający ocenił PR, ale nie podał uzasadnienia, więc werdyktowi nie można było zaufać na tyle, by scalić automatycznie; PR czeka na scalenie przez człowieka.",
|
|
813
823
|
"no_assessment": "Scalający nie zwrócił możliwej do przetworzenia oceny, więc PR czeka na scalenie przez człowieka.",
|
|
814
|
-
"merge_failed": "Oceny mieściły się w progach {preset}, ale automatyczne scalenie nie mogło się powieść (np. ochrona gałęzi lub konflikt), więc PR czeka na scalenie przez człowieka."
|
|
824
|
+
"merge_failed": "Oceny mieściły się w progach {preset}, ale automatyczne scalenie nie mogło się powieść (np. ochrona gałęzi lub konflikt), więc PR czeka na scalenie przez człowieka.",
|
|
825
|
+
"merge_partial": "Część pull requestów zadania została scalona, ale kolejnego nie udało się scalić, więc zmiana czeka, aż człowiek dokończy lub cofnie scalanie wielorepozytoryjne."
|
|
815
826
|
},
|
|
816
827
|
"scores": "Oceny",
|
|
817
828
|
"axis": {
|
|
@@ -4048,6 +4059,26 @@
|
|
|
4048
4059
|
"hint": "Kontynuuj pozwala planiscie zadac kolejne pytania; Przejdz do planowania planuje na podstawie dotychczasowych odpowiedzi.",
|
|
4049
4060
|
"proceed": "Przejdz do planowania",
|
|
4050
4061
|
"continue": "Kontynuuj"
|
|
4062
|
+
},
|
|
4063
|
+
"followUpStatus": {
|
|
4064
|
+
"open": "Otwarte",
|
|
4065
|
+
"promoted": "Awansowane",
|
|
4066
|
+
"dismissed": "Odrzucone"
|
|
4067
|
+
},
|
|
4068
|
+
"curation": {
|
|
4069
|
+
"promote": "Awansuj do elementu",
|
|
4070
|
+
"promoteConfirm": "Utworz element",
|
|
4071
|
+
"dismiss": "Odrzuc",
|
|
4072
|
+
"retry": "Ponow",
|
|
4073
|
+
"skip": "Pomin",
|
|
4074
|
+
"edit": "Edytuj",
|
|
4075
|
+
"save": "Zapisz",
|
|
4076
|
+
"cancel": "Anuluj",
|
|
4077
|
+
"phaseField": "Faza",
|
|
4078
|
+
"itemTitlePlaceholder": "Tytul elementu (domyslnie z zadania nastepczego)",
|
|
4079
|
+
"maxConcurrentField": "Maks. rownoczesnych zadan",
|
|
4080
|
+
"defaultPipelineField": "Domyslny pipeline",
|
|
4081
|
+
"failed": "Nie udalo sie zaktualizowac inicjatywy"
|
|
4051
4082
|
}
|
|
4052
4083
|
}
|
|
4053
4084
|
}
|
package/i18n/locales/tr.json
CHANGED
|
@@ -198,7 +198,17 @@
|
|
|
198
198
|
"submit": "Yinelenen pipeline ekle",
|
|
199
199
|
"addFailedTitle": "Yinelenen pipeline eklenemedi",
|
|
200
200
|
"onDemand": "İstek üzerine (yalnızca manuel)",
|
|
201
|
-
"onDemandHint": "Yalnızca siz tetiklediğinizde çalışır, zamanlama yoktur. Her seferinde siz hazır bulunduğunuz için görevi bireysel kullanımlı bir abonelik modeli kullanabilir."
|
|
201
|
+
"onDemandHint": "Yalnızca siz tetiklediğinizde çalışır, zamanlama yoktur. Her seferinde siz hazır bulunduğunuz için görevi bireysel kullanımlı bir abonelik modeli kullanabilir.",
|
|
202
|
+
"intake": "Sorun alımı",
|
|
203
|
+
"intakeHint": "Her çalıştırma, izleyiciden eşleşen açık bir sorunu seçer ve baştan sona işler.",
|
|
204
|
+
"intakeNoSources": "Sorunları çekmek için önce bir görev kaynağı bağlayın.",
|
|
205
|
+
"intakeGithubRepo": "Depo",
|
|
206
|
+
"intakeTitleFragment": "Başlık şunu içerir",
|
|
207
|
+
"intakeTitleFragmentPlaceholder": "örn. crash",
|
|
208
|
+
"intakeLabels": "Etiketler",
|
|
209
|
+
"intakeLabelsPlaceholder": "virgülle ayrılmış",
|
|
210
|
+
"intakeIssueType": "Sorun türü",
|
|
211
|
+
"intakeInProgressLabel": "Devam ediyor etiketi"
|
|
202
212
|
},
|
|
203
213
|
"failure": {
|
|
204
214
|
"containerFailedToStart": "Konteyner başlatılamadı",
|
|
@@ -811,7 +821,8 @@
|
|
|
811
821
|
"auto_merge_disabled": "{preset} ön ayarı her PR'yi bir kişiye yönlendirir, bu yüzden bu PR inceleme bekliyor.",
|
|
812
822
|
"no_rationale": "Birleştirici PR'yi puanladı ancak bir gerekçe vermedi, bu yüzden karara otomatik birleştirme için güvenilemedi; PR bir kişinin birleştirmesini bekliyor.",
|
|
813
823
|
"no_assessment": "Birleştirici ayrıştırılabilir bir değerlendirme döndürmedi, bu yüzden PR bir kişinin birleştirmesini bekliyor.",
|
|
814
|
-
"merge_failed": "Puanlar {preset} eşiklerinin içindeydi ancak otomatik birleştirme tamamlanamadı (örneğin dal koruması veya bir çakışma), bu yüzden PR bir kişinin birleştirmesini bekliyor."
|
|
824
|
+
"merge_failed": "Puanlar {preset} eşiklerinin içindeydi ancak otomatik birleştirme tamamlanamadı (örneğin dal koruması veya bir çakışma), bu yüzden PR bir kişinin birleştirmesini bekliyor.",
|
|
825
|
+
"merge_partial": "Görevin bazı pull request'leri birleştirildi ancak sonraki biri birleştirilemedi, bu yüzden değişiklik bir kişinin çoklu depo birleştirmesini tamamlamasını veya geri almasını bekliyor."
|
|
815
826
|
},
|
|
816
827
|
"scores": "Puanlar",
|
|
817
828
|
"axis": {
|
|
@@ -4060,6 +4071,26 @@
|
|
|
4060
4071
|
"hint": "Devam et, planlayicinin ek sorular sormasini saglar; Planlamaya gec, mevcut yanitlarla planlar.",
|
|
4061
4072
|
"proceed": "Planlamaya gec",
|
|
4062
4073
|
"continue": "Devam et"
|
|
4074
|
+
},
|
|
4075
|
+
"followUpStatus": {
|
|
4076
|
+
"open": "Acik",
|
|
4077
|
+
"promoted": "Yukseltildi",
|
|
4078
|
+
"dismissed": "Yoksayildi"
|
|
4079
|
+
},
|
|
4080
|
+
"curation": {
|
|
4081
|
+
"promote": "Ogeye yukselt",
|
|
4082
|
+
"promoteConfirm": "Oge olustur",
|
|
4083
|
+
"dismiss": "Yoksay",
|
|
4084
|
+
"retry": "Yeniden dene",
|
|
4085
|
+
"skip": "Atla",
|
|
4086
|
+
"edit": "Duzenle",
|
|
4087
|
+
"save": "Kaydet",
|
|
4088
|
+
"cancel": "Iptal",
|
|
4089
|
+
"phaseField": "Asama",
|
|
4090
|
+
"itemTitlePlaceholder": "Oge basligi (varsayilan: takip ogesininki)",
|
|
4091
|
+
"maxConcurrentField": "Maks. es zamanli gorev",
|
|
4092
|
+
"defaultPipelineField": "Varsayilan pipeline",
|
|
4093
|
+
"failed": "Girisim guncellenemedi"
|
|
4063
4094
|
}
|
|
4064
4095
|
}
|
|
4065
4096
|
}
|
package/i18n/locales/uk.json
CHANGED
|
@@ -198,7 +198,17 @@
|
|
|
198
198
|
"submit": "Додати періодичний конвеєр",
|
|
199
199
|
"addFailedTitle": "Не вдалося додати періодичний конвеєр",
|
|
200
200
|
"onDemand": "За запитом (лише вручну)",
|
|
201
|
-
"onDemandHint": "Запускається лише коли ви його активуєте, без розкладу. Оскільки ви присутні щоразу, його завдання може використовувати модель підписки для індивідуального використання."
|
|
201
|
+
"onDemandHint": "Запускається лише коли ви його активуєте, без розкладу. Оскільки ви присутні щоразу, його завдання може використовувати модель підписки для індивідуального використання.",
|
|
202
|
+
"intake": "Приймання завдань",
|
|
203
|
+
"intakeHint": "Кожен запуск вибирає одне відкрите завдання з трекера, що відповідає умовам, і опрацьовує його від початку до кінця.",
|
|
204
|
+
"intakeNoSources": "Спочатку підключіть джерело завдань, щоб отримувати з нього завдання.",
|
|
205
|
+
"intakeGithubRepo": "Репозиторій",
|
|
206
|
+
"intakeTitleFragment": "Заголовок містить",
|
|
207
|
+
"intakeTitleFragmentPlaceholder": "напр. crash",
|
|
208
|
+
"intakeLabels": "Мітки",
|
|
209
|
+
"intakeLabelsPlaceholder": "через кому",
|
|
210
|
+
"intakeIssueType": "Тип завдання",
|
|
211
|
+
"intakeInProgressLabel": "Мітка «в роботі»"
|
|
202
212
|
},
|
|
203
213
|
"failure": {
|
|
204
214
|
"containerFailedToStart": "Не вдалося запустити контейнер",
|
|
@@ -811,7 +821,8 @@
|
|
|
811
821
|
"auto_merge_disabled": "Пресет {preset} надсилає кожен PR людині, тож цей очікує на перевірку.",
|
|
812
822
|
"no_rationale": "Модуль злиття оцінив PR, але не надав обґрунтування, тому вердикту не можна було довіряти для автоматичного злиття; PR очікує на злиття людиною.",
|
|
813
823
|
"no_assessment": "Модуль злиття не повернув придатну для обробки оцінку, тому PR очікує на злиття людиною.",
|
|
814
|
-
"merge_failed": "Оцінки були в межах порогів {preset}, але автоматичне злиття не вдалося завершити (наприклад, захист гілки або конфлікт), тому PR очікує на злиття людиною."
|
|
824
|
+
"merge_failed": "Оцінки були в межах порогів {preset}, але автоматичне злиття не вдалося завершити (наприклад, захист гілки або конфлікт), тому PR очікує на злиття людиною.",
|
|
825
|
+
"merge_partial": "Частину пул-реквестів завдання злито, але наступний не вдалося, тому зміна очікує, поки людина завершить або скасує багаторепозиторне злиття."
|
|
815
826
|
},
|
|
816
827
|
"scores": "Оцінки",
|
|
817
828
|
"axis": {
|
|
@@ -4048,6 +4059,26 @@
|
|
|
4048
4059
|
"hint": "Продовжити дозволяє планувальнику ставити додаткові питання; Перейти до планування планує з наявними відповідями.",
|
|
4049
4060
|
"proceed": "Перейти до планування",
|
|
4050
4061
|
"continue": "Продовжити"
|
|
4062
|
+
},
|
|
4063
|
+
"followUpStatus": {
|
|
4064
|
+
"open": "Відкрито",
|
|
4065
|
+
"promoted": "Підвищено",
|
|
4066
|
+
"dismissed": "Відхилено"
|
|
4067
|
+
},
|
|
4068
|
+
"curation": {
|
|
4069
|
+
"promote": "Підвищити до елемента",
|
|
4070
|
+
"promoteConfirm": "Створити елемент",
|
|
4071
|
+
"dismiss": "Відхилити",
|
|
4072
|
+
"retry": "Повторити",
|
|
4073
|
+
"skip": "Пропустити",
|
|
4074
|
+
"edit": "Редагувати",
|
|
4075
|
+
"save": "Зберегти",
|
|
4076
|
+
"cancel": "Скасувати",
|
|
4077
|
+
"phaseField": "Фаза",
|
|
4078
|
+
"itemTitlePlaceholder": "Назва елемента (типово — з подальшого завдання)",
|
|
4079
|
+
"maxConcurrentField": "Макс. одночасних завдань",
|
|
4080
|
+
"defaultPipelineField": "Типовий конвеєр",
|
|
4081
|
+
"failed": "Не вдалося оновити ініціативу"
|
|
4051
4082
|
}
|
|
4052
4083
|
}
|
|
4053
4084
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cat-factory/app",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.88.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",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"valibot": "^1.4.2",
|
|
35
35
|
"vue": "^3.5.39",
|
|
36
36
|
"wretch": "^3.0.9",
|
|
37
|
-
"@cat-factory/contracts": "0.
|
|
37
|
+
"@cat-factory/contracts": "0.96.0"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@toad-contracts/testing": "0.3.2",
|