@cat-factory/app 0.87.4 → 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/components/panels/inspector/ServiceFragments.vue +11 -15
- package/app/components/panels/inspector/TaskStructure.vue +15 -15
- package/app/components/settings/ServiceFragmentDefaultsPanel.vue +3 -9
- 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/fragmentPicker.spec.ts +60 -0
- package/app/utils/fragmentPicker.ts +32 -0
- 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
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
// services — each owns its selection from creation. Persisted via the
|
|
7
7
|
// serviceFragmentDefaults store (the backend replaces the whole list on each change).
|
|
8
8
|
import { onMounted, ref } from 'vue'
|
|
9
|
+
import { buildFragmentPickerGroups } from '~/utils/fragmentPicker'
|
|
9
10
|
|
|
10
11
|
const { t } = useI18n()
|
|
11
12
|
const fragments = useFragmentsStore()
|
|
@@ -24,17 +25,10 @@ const selected = computed(() =>
|
|
|
24
25
|
defaults.fragmentIds.map((id) => fragments.getFragment(id) ?? { id, title: id, summary: '' }),
|
|
25
26
|
)
|
|
26
27
|
|
|
27
|
-
// Pool fragments not already in the default set, grouped
|
|
28
|
+
// Pool fragments not already in the default set, grouped into labelled per-category sections.
|
|
28
29
|
const menu = computed(() => {
|
|
29
30
|
const chosen = new Set(defaults.fragmentIds)
|
|
30
|
-
|
|
31
|
-
for (const f of fragments.fragments) {
|
|
32
|
-
if (chosen.has(f.id)) continue
|
|
33
|
-
const items = groups.get(f.category) ?? []
|
|
34
|
-
items.push({ label: f.title, onSelect: () => add(f.id) })
|
|
35
|
-
groups.set(f.category, items)
|
|
36
|
-
}
|
|
37
|
-
return [...groups.values()]
|
|
31
|
+
return buildFragmentPickerGroups(fragments.fragments, (id) => chosen.has(id), add)
|
|
38
32
|
})
|
|
39
33
|
|
|
40
34
|
async function save(ids: string[]) {
|
|
@@ -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',
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import type { PromptFragment } from '~/types/domain'
|
|
3
|
+
import { buildFragmentPickerGroups } from './fragmentPicker'
|
|
4
|
+
|
|
5
|
+
const frag = (id: string, category: string, title = id): PromptFragment =>
|
|
6
|
+
({ id, version: '1.0.0', title, category, summary: '', body: '' }) as PromptFragment
|
|
7
|
+
|
|
8
|
+
const pool: PromptFragment[] = [
|
|
9
|
+
frag('node.best-practices', 'Node', 'Node best practices'),
|
|
10
|
+
frag('node.performance', 'Node', 'Node performance'),
|
|
11
|
+
frag('style.anti-llmisms', 'Writing style', 'Avoid LLM tells'),
|
|
12
|
+
frag('style.concise-actionable', 'Writing style', 'Concise and actionable'),
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
describe('buildFragmentPickerGroups', () => {
|
|
16
|
+
it('buckets fragments into one labelled group per category (technical + writing-style tracks)', () => {
|
|
17
|
+
const groups = buildFragmentPickerGroups(
|
|
18
|
+
pool,
|
|
19
|
+
() => false,
|
|
20
|
+
() => {},
|
|
21
|
+
)
|
|
22
|
+
// One group per category, each led by a non-interactive `type: 'label'` heading.
|
|
23
|
+
expect(groups.map((g) => g[0])).toEqual([
|
|
24
|
+
{ type: 'label', label: 'Node' },
|
|
25
|
+
{ type: 'label', label: 'Writing style' },
|
|
26
|
+
])
|
|
27
|
+
// The heading is followed by that category's item labels, in pool order.
|
|
28
|
+
expect(groups[0]!.slice(1).map((i) => i.label)).toEqual([
|
|
29
|
+
'Node best practices',
|
|
30
|
+
'Node performance',
|
|
31
|
+
])
|
|
32
|
+
expect(groups[1]!.slice(1).map((i) => i.label)).toEqual([
|
|
33
|
+
'Avoid LLM tells',
|
|
34
|
+
'Concise and actionable',
|
|
35
|
+
])
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it('omits already-selected fragments, dropping a category that empties out', () => {
|
|
39
|
+
const selected = new Set(['style.anti-llmisms', 'style.concise-actionable'])
|
|
40
|
+
const groups = buildFragmentPickerGroups(
|
|
41
|
+
pool,
|
|
42
|
+
(id) => selected.has(id),
|
|
43
|
+
() => {},
|
|
44
|
+
)
|
|
45
|
+
// Writing style fully selected → its category disappears entirely (no empty labelled group).
|
|
46
|
+
expect(groups.map((g) => g[0])).toEqual([{ type: 'label', label: 'Node' }])
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
it('invokes onSelect with the fragment id when an item is chosen', () => {
|
|
50
|
+
const picked: string[] = []
|
|
51
|
+
const groups = buildFragmentPickerGroups(
|
|
52
|
+
pool,
|
|
53
|
+
() => false,
|
|
54
|
+
(id) => picked.push(id),
|
|
55
|
+
)
|
|
56
|
+
// Fire the first real item under the first category (index 1, past the label heading).
|
|
57
|
+
;(groups[0]![1] as { onSelect: () => void }).onSelect()
|
|
58
|
+
expect(picked).toEqual(['node.best-practices'])
|
|
59
|
+
})
|
|
60
|
+
})
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { DropdownMenuItem } from '@nuxt/ui'
|
|
2
|
+
import type { PromptFragment } from '~/types/domain'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Build the category-grouped groups for a fragment "add" dropdown: the pool fragments not
|
|
6
|
+
* already selected, bucketed by `category`, each bucket prefixed with a non-interactive
|
|
7
|
+
* `type: 'label'` heading so the catalog reads as labelled sections instead of one flat,
|
|
8
|
+
* undifferentiated list. This matters now that the catalog spans distinct tracks that a
|
|
9
|
+
* single block can pin together — the technical collections (Node / React / …) AND the
|
|
10
|
+
* document Writing-style fragments — so the headings keep the longer, mixed list navigable.
|
|
11
|
+
*
|
|
12
|
+
* Category order follows first appearance in `pool`; empty categories are dropped. Each
|
|
13
|
+
* inner array is one Nuxt UI menu group (rendered divider-separated); callers append their
|
|
14
|
+
* own trailing groups (e.g. the library-management links) after the returned groups.
|
|
15
|
+
*/
|
|
16
|
+
export function buildFragmentPickerGroups(
|
|
17
|
+
pool: PromptFragment[],
|
|
18
|
+
isSelected: (id: string) => boolean,
|
|
19
|
+
onSelect: (id: string) => void,
|
|
20
|
+
): DropdownMenuItem[][] {
|
|
21
|
+
const groups = new Map<string, DropdownMenuItem[]>()
|
|
22
|
+
for (const f of pool) {
|
|
23
|
+
if (isSelected(f.id)) continue
|
|
24
|
+
const items = groups.get(f.category) ?? []
|
|
25
|
+
items.push({ label: f.title, onSelect: () => onSelect(f.id) })
|
|
26
|
+
groups.set(f.category, items)
|
|
27
|
+
}
|
|
28
|
+
return [...groups.entries()].map(([category, items]): DropdownMenuItem[] => [
|
|
29
|
+
{ type: 'label', label: category },
|
|
30
|
+
...items,
|
|
31
|
+
])
|
|
32
|
+
}
|
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
|
}
|