@cat-factory/app 0.119.0 → 0.120.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/AddTaskModal.vue +78 -12
- package/app/utils/catalog.spec.ts +1 -0
- package/app/utils/catalog.ts +13 -0
- package/i18n/locales/de.json +14 -0
- package/i18n/locales/en.json +14 -0
- package/i18n/locales/es.json +14 -0
- package/i18n/locales/fr.json +14 -0
- package/i18n/locales/he.json +14 -0
- package/i18n/locales/it.json +14 -0
- package/i18n/locales/ja.json +14 -0
- package/i18n/locales/pl.json +14 -0
- package/i18n/locales/tr.json +14 -0
- package/i18n/locales/uk.json +14 -0
- package/package.json +2 -2
|
@@ -102,6 +102,13 @@ const isRecurring = computed(() => taskType.value === 'recurring')
|
|
|
102
102
|
const severity = ref<'low' | 'medium' | 'high' | 'critical' | ''>('')
|
|
103
103
|
const stepsToReproduce = ref('')
|
|
104
104
|
const timeboxHours = ref<number | undefined>(undefined)
|
|
105
|
+
// Spike research criteria — folded into the spike agent's prompt (see the backend `spike` kind).
|
|
106
|
+
const spikeResearchQuestion = ref('')
|
|
107
|
+
const spikeSuccessCriteria = ref('')
|
|
108
|
+
const spikeOptionsToCompare = ref('')
|
|
109
|
+
// Optional in-repo path the findings document is committed to (else `docs/research/<slug>.md`);
|
|
110
|
+
// shares the `taskTypeFields.targetPath` field + its safe-`.md`-path validation with `document`.
|
|
111
|
+
const spikeTargetPath = ref('')
|
|
105
112
|
// `DOC_KINDS` (and the `DocKind` type) are owned by the contracts package — re-exported via
|
|
106
113
|
// `~/types/domain` — so the picker and the create payload can't drift from the backend list.
|
|
107
114
|
const docKind = ref<DocKind | ''>('')
|
|
@@ -171,13 +178,21 @@ function buildTypeFields(): TaskTypeFields | undefined {
|
|
|
171
178
|
return Object.keys(f).length ? f : undefined
|
|
172
179
|
}
|
|
173
180
|
if (taskType.value === 'spike') {
|
|
181
|
+
const f: TaskTypeFields = {}
|
|
174
182
|
// `v-model.number` on a cleared number input yields '' (not undefined), which would
|
|
175
183
|
// serialise as a non-number and 400 the create — so require a finite number here.
|
|
176
|
-
|
|
184
|
+
if (
|
|
185
|
+
typeof timeboxHours.value === 'number' &&
|
|
177
186
|
Number.isFinite(timeboxHours.value) &&
|
|
178
187
|
timeboxHours.value >= 0
|
|
179
|
-
|
|
180
|
-
|
|
188
|
+
) {
|
|
189
|
+
f.timeboxHours = timeboxHours.value
|
|
190
|
+
}
|
|
191
|
+
if (spikeResearchQuestion.value.trim()) f.researchQuestion = spikeResearchQuestion.value.trim()
|
|
192
|
+
if (spikeSuccessCriteria.value.trim()) f.successCriteria = spikeSuccessCriteria.value.trim()
|
|
193
|
+
if (spikeOptionsToCompare.value.trim()) f.optionsToCompare = spikeOptionsToCompare.value.trim()
|
|
194
|
+
if (spikeTargetPath.value.trim()) f.targetPath = spikeTargetPath.value.trim()
|
|
195
|
+
return Object.keys(f).length ? f : undefined
|
|
181
196
|
}
|
|
182
197
|
if (taskType.value === 'document') {
|
|
183
198
|
const f: TaskTypeFields = {}
|
|
@@ -406,6 +421,10 @@ watch(open, (isOpen) => {
|
|
|
406
421
|
severity.value = ''
|
|
407
422
|
stepsToReproduce.value = ''
|
|
408
423
|
timeboxHours.value = undefined
|
|
424
|
+
spikeResearchQuestion.value = ''
|
|
425
|
+
spikeSuccessCriteria.value = ''
|
|
426
|
+
spikeOptionsToCompare.value = ''
|
|
427
|
+
spikeTargetPath.value = ''
|
|
409
428
|
docKind.value = ''
|
|
410
429
|
docAudience.value = ''
|
|
411
430
|
docTargetPath.value = ''
|
|
@@ -451,6 +470,10 @@ const { requestClose } = useUnsavedGuard({
|
|
|
451
470
|
severity: severity.value,
|
|
452
471
|
stepsToReproduce: stepsToReproduce.value.trim(),
|
|
453
472
|
timeboxHours: timeboxHours.value ?? null,
|
|
473
|
+
spikeResearchQuestion: spikeResearchQuestion.value.trim(),
|
|
474
|
+
spikeSuccessCriteria: spikeSuccessCriteria.value.trim(),
|
|
475
|
+
spikeOptionsToCompare: spikeOptionsToCompare.value.trim(),
|
|
476
|
+
spikeTargetPath: spikeTargetPath.value.trim(),
|
|
454
477
|
docKind: docKind.value,
|
|
455
478
|
docAudience: docAudience.value.trim(),
|
|
456
479
|
docTargetPath: docTargetPath.value.trim(),
|
|
@@ -671,15 +694,58 @@ async function add() {
|
|
|
671
694
|
</UFormField>
|
|
672
695
|
</div>
|
|
673
696
|
|
|
674
|
-
<
|
|
675
|
-
<
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
697
|
+
<div v-else-if="taskType === 'spike'" class="space-y-3">
|
|
698
|
+
<UFormField :label="t('board.addTask.timebox')">
|
|
699
|
+
<UInput
|
|
700
|
+
v-model.number="timeboxHours"
|
|
701
|
+
type="number"
|
|
702
|
+
min="0"
|
|
703
|
+
:placeholder="t('board.addTask.timeboxPlaceholder')"
|
|
704
|
+
class="w-full"
|
|
705
|
+
/>
|
|
706
|
+
</UFormField>
|
|
707
|
+
<UFormField
|
|
708
|
+
:label="t('board.addTask.spikeFields.researchQuestion.label')"
|
|
709
|
+
:hint="t('board.addTask.optional')"
|
|
710
|
+
>
|
|
711
|
+
<UInput
|
|
712
|
+
v-model="spikeResearchQuestion"
|
|
713
|
+
:placeholder="t('board.addTask.spikeFields.researchQuestion.placeholder')"
|
|
714
|
+
class="w-full"
|
|
715
|
+
/>
|
|
716
|
+
</UFormField>
|
|
717
|
+
<UFormField
|
|
718
|
+
:label="t('board.addTask.spikeFields.successCriteria.label')"
|
|
719
|
+
:hint="t('board.addTask.optional')"
|
|
720
|
+
>
|
|
721
|
+
<UTextarea
|
|
722
|
+
v-model="spikeSuccessCriteria"
|
|
723
|
+
:rows="2"
|
|
724
|
+
autoresize
|
|
725
|
+
:placeholder="t('board.addTask.spikeFields.successCriteria.placeholder')"
|
|
726
|
+
class="w-full"
|
|
727
|
+
/>
|
|
728
|
+
</UFormField>
|
|
729
|
+
<UFormField
|
|
730
|
+
:label="t('board.addTask.spikeFields.optionsToCompare.label')"
|
|
731
|
+
:hint="t('board.addTask.optional')"
|
|
732
|
+
>
|
|
733
|
+
<UTextarea
|
|
734
|
+
v-model="spikeOptionsToCompare"
|
|
735
|
+
:rows="2"
|
|
736
|
+
autoresize
|
|
737
|
+
:placeholder="t('board.addTask.spikeFields.optionsToCompare.placeholder')"
|
|
738
|
+
class="w-full"
|
|
739
|
+
/>
|
|
740
|
+
</UFormField>
|
|
741
|
+
<UFormField :label="t('board.addTask.targetPath')" :hint="t('board.addTask.optional')">
|
|
742
|
+
<UInput
|
|
743
|
+
v-model="spikeTargetPath"
|
|
744
|
+
:placeholder="t('board.addTask.targetPathPlaceholder')"
|
|
745
|
+
class="w-full"
|
|
746
|
+
/>
|
|
747
|
+
</UFormField>
|
|
748
|
+
</div>
|
|
683
749
|
|
|
684
750
|
<div v-else-if="taskType === 'document'" class="space-y-3">
|
|
685
751
|
<UFormField :label="t('board.addTask.documentKind')">
|
package/app/utils/catalog.ts
CHANGED
|
@@ -64,6 +64,19 @@ export const AGENT_ARCHETYPES: AgentArchetype[] = [
|
|
|
64
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
65
|
resultView: 'generic-structured',
|
|
66
66
|
},
|
|
67
|
+
{
|
|
68
|
+
// A timeboxed read-only research/investigation agent. Its structured findings open in the
|
|
69
|
+
// shared generic viewer; the findings document is committed by a backend post-op (delivered
|
|
70
|
+
// as a pull request by default, or straight to base via the direct pipeline).
|
|
71
|
+
kind: 'spike',
|
|
72
|
+
label: 'Spike',
|
|
73
|
+
icon: 'i-lucide-flask-conical',
|
|
74
|
+
color: '#22d3ee',
|
|
75
|
+
category: 'design',
|
|
76
|
+
description:
|
|
77
|
+
'Timeboxed read-only investigation that answers a research question against the context and codebase, and delivers a findings document (as a pull request by default; no code).',
|
|
78
|
+
resultView: 'generic-structured',
|
|
79
|
+
},
|
|
67
80
|
{
|
|
68
81
|
kind: 'task-estimator',
|
|
69
82
|
label: 'Task Estimator',
|
package/i18n/locales/de.json
CHANGED
|
@@ -2064,6 +2064,20 @@
|
|
|
2064
2064
|
"placeholder": "Die Endpoints oder die Oberfläche im Geltungsbereich"
|
|
2065
2065
|
}
|
|
2066
2066
|
},
|
|
2067
|
+
"spikeFields": {
|
|
2068
|
+
"researchQuestion": {
|
|
2069
|
+
"label": "Forschungsfrage",
|
|
2070
|
+
"placeholder": "Die Frage oder Hypothese, die der Spike beantworten soll"
|
|
2071
|
+
},
|
|
2072
|
+
"successCriteria": {
|
|
2073
|
+
"label": "Erfolgskriterien",
|
|
2074
|
+
"placeholder": "Die Akzeptanzkriterien oder die Entscheidung, die die Ergebnisse stützen sollen"
|
|
2075
|
+
},
|
|
2076
|
+
"optionsToCompare": {
|
|
2077
|
+
"label": "Zu vergleichende Optionen",
|
|
2078
|
+
"placeholder": "Die gegeneinander abzuwägenden Optionen"
|
|
2079
|
+
}
|
|
2080
|
+
},
|
|
2067
2081
|
"optional": "optional",
|
|
2068
2082
|
"pipeline": "Pipeline",
|
|
2069
2083
|
"chooseAtRunTime": "Zur Laufzeit auswählen",
|
package/i18n/locales/en.json
CHANGED
|
@@ -258,6 +258,20 @@
|
|
|
258
258
|
"placeholder": "The endpoints or surface in scope"
|
|
259
259
|
}
|
|
260
260
|
},
|
|
261
|
+
"spikeFields": {
|
|
262
|
+
"researchQuestion": {
|
|
263
|
+
"label": "Research question",
|
|
264
|
+
"placeholder": "The question or hypothesis the spike must answer"
|
|
265
|
+
},
|
|
266
|
+
"successCriteria": {
|
|
267
|
+
"label": "Success criteria",
|
|
268
|
+
"placeholder": "The acceptance criteria or the decision the findings must inform"
|
|
269
|
+
},
|
|
270
|
+
"optionsToCompare": {
|
|
271
|
+
"label": "Options to compare",
|
|
272
|
+
"placeholder": "The options to weigh against each other"
|
|
273
|
+
}
|
|
274
|
+
},
|
|
261
275
|
"optional": "optional",
|
|
262
276
|
"pipeline": "Pipeline",
|
|
263
277
|
"chooseAtRunTime": "Choose at run time",
|
package/i18n/locales/es.json
CHANGED
|
@@ -240,6 +240,20 @@
|
|
|
240
240
|
"placeholder": "Los endpoints o la superficie dentro del alcance"
|
|
241
241
|
}
|
|
242
242
|
},
|
|
243
|
+
"spikeFields": {
|
|
244
|
+
"researchQuestion": {
|
|
245
|
+
"label": "Pregunta de investigación",
|
|
246
|
+
"placeholder": "La pregunta o hipótesis que el spike debe responder"
|
|
247
|
+
},
|
|
248
|
+
"successCriteria": {
|
|
249
|
+
"label": "Criterios de éxito",
|
|
250
|
+
"placeholder": "Los criterios de aceptación o la decisión que deben fundamentar los hallazgos"
|
|
251
|
+
},
|
|
252
|
+
"optionsToCompare": {
|
|
253
|
+
"label": "Opciones a comparar",
|
|
254
|
+
"placeholder": "Las opciones a sopesar entre sí"
|
|
255
|
+
}
|
|
256
|
+
},
|
|
243
257
|
"optional": "opcional",
|
|
244
258
|
"pipeline": "Pipeline",
|
|
245
259
|
"chooseAtRunTime": "Elegir al ejecutar",
|
package/i18n/locales/fr.json
CHANGED
|
@@ -240,6 +240,20 @@
|
|
|
240
240
|
"placeholder": "Les endpoints ou la surface concernés"
|
|
241
241
|
}
|
|
242
242
|
},
|
|
243
|
+
"spikeFields": {
|
|
244
|
+
"researchQuestion": {
|
|
245
|
+
"label": "Question de recherche",
|
|
246
|
+
"placeholder": "La question ou l'hypothèse à laquelle le spike doit répondre"
|
|
247
|
+
},
|
|
248
|
+
"successCriteria": {
|
|
249
|
+
"label": "Critères de réussite",
|
|
250
|
+
"placeholder": "Les critères d'acceptation ou la décision que les conclusions doivent éclairer"
|
|
251
|
+
},
|
|
252
|
+
"optionsToCompare": {
|
|
253
|
+
"label": "Options à comparer",
|
|
254
|
+
"placeholder": "Les options à mettre en balance"
|
|
255
|
+
}
|
|
256
|
+
},
|
|
243
257
|
"optional": "optionnel",
|
|
244
258
|
"pipeline": "Pipeline",
|
|
245
259
|
"chooseAtRunTime": "Choisir au lancement",
|
package/i18n/locales/he.json
CHANGED
|
@@ -240,6 +240,20 @@
|
|
|
240
240
|
"placeholder": "נקודות הקצה או המשטח שבתחום"
|
|
241
241
|
}
|
|
242
242
|
},
|
|
243
|
+
"spikeFields": {
|
|
244
|
+
"researchQuestion": {
|
|
245
|
+
"label": "שאלת מחקר",
|
|
246
|
+
"placeholder": "השאלה או ההשערה שעל הספייק לענות עליה"
|
|
247
|
+
},
|
|
248
|
+
"successCriteria": {
|
|
249
|
+
"label": "קריטריוני הצלחה",
|
|
250
|
+
"placeholder": "קריטריוני הקבלה או ההחלטה שהממצאים צריכים לבסס"
|
|
251
|
+
},
|
|
252
|
+
"optionsToCompare": {
|
|
253
|
+
"label": "אפשרויות להשוואה",
|
|
254
|
+
"placeholder": "האפשרויות שיש לשקול זו מול זו"
|
|
255
|
+
}
|
|
256
|
+
},
|
|
243
257
|
"optional": "אופציונלי",
|
|
244
258
|
"pipeline": "צינור",
|
|
245
259
|
"chooseAtRunTime": "בחר בזמן הריצה",
|
package/i18n/locales/it.json
CHANGED
|
@@ -2064,6 +2064,20 @@
|
|
|
2064
2064
|
"placeholder": "Gli endpoint o la superficie in ambito"
|
|
2065
2065
|
}
|
|
2066
2066
|
},
|
|
2067
|
+
"spikeFields": {
|
|
2068
|
+
"researchQuestion": {
|
|
2069
|
+
"label": "Domanda di ricerca",
|
|
2070
|
+
"placeholder": "La domanda o l'ipotesi a cui lo spike deve rispondere"
|
|
2071
|
+
},
|
|
2072
|
+
"successCriteria": {
|
|
2073
|
+
"label": "Criteri di successo",
|
|
2074
|
+
"placeholder": "I criteri di accettazione o la decisione che i risultati devono supportare"
|
|
2075
|
+
},
|
|
2076
|
+
"optionsToCompare": {
|
|
2077
|
+
"label": "Opzioni da confrontare",
|
|
2078
|
+
"placeholder": "Le opzioni da valutare l'una rispetto all'altra"
|
|
2079
|
+
}
|
|
2080
|
+
},
|
|
2067
2081
|
"optional": "opzionale",
|
|
2068
2082
|
"pipeline": "Pipeline",
|
|
2069
2083
|
"chooseAtRunTime": "Scegli al momento dell'esecuzione",
|
package/i18n/locales/ja.json
CHANGED
|
@@ -240,6 +240,20 @@
|
|
|
240
240
|
"placeholder": "対象となるエンドポイントや範囲"
|
|
241
241
|
}
|
|
242
242
|
},
|
|
243
|
+
"spikeFields": {
|
|
244
|
+
"researchQuestion": {
|
|
245
|
+
"label": "調査課題",
|
|
246
|
+
"placeholder": "スパイクで答えるべき問いや仮説"
|
|
247
|
+
},
|
|
248
|
+
"successCriteria": {
|
|
249
|
+
"label": "成功基準",
|
|
250
|
+
"placeholder": "受け入れ基準、または調査結果が判断材料とすべき決定事項"
|
|
251
|
+
},
|
|
252
|
+
"optionsToCompare": {
|
|
253
|
+
"label": "比較する選択肢",
|
|
254
|
+
"placeholder": "互いに比較検討する選択肢"
|
|
255
|
+
}
|
|
256
|
+
},
|
|
243
257
|
"optional": "任意",
|
|
244
258
|
"pipeline": "パイプライン",
|
|
245
259
|
"chooseAtRunTime": "実行時に選択",
|
package/i18n/locales/pl.json
CHANGED
|
@@ -240,6 +240,20 @@
|
|
|
240
240
|
"placeholder": "Endpointy lub zakres objęty dokumentem"
|
|
241
241
|
}
|
|
242
242
|
},
|
|
243
|
+
"spikeFields": {
|
|
244
|
+
"researchQuestion": {
|
|
245
|
+
"label": "Pytanie badawcze",
|
|
246
|
+
"placeholder": "Pytanie lub hipoteza, na które ma odpowiedzieć spike"
|
|
247
|
+
},
|
|
248
|
+
"successCriteria": {
|
|
249
|
+
"label": "Kryteria sukcesu",
|
|
250
|
+
"placeholder": "Kryteria akceptacji lub decyzja, którą mają uzasadnić wyniki"
|
|
251
|
+
},
|
|
252
|
+
"optionsToCompare": {
|
|
253
|
+
"label": "Opcje do porównania",
|
|
254
|
+
"placeholder": "Opcje do rozważenia względem siebie"
|
|
255
|
+
}
|
|
256
|
+
},
|
|
243
257
|
"optional": "opcjonalne",
|
|
244
258
|
"pipeline": "Pipeline",
|
|
245
259
|
"chooseAtRunTime": "Wybierz przy uruchomieniu",
|
package/i18n/locales/tr.json
CHANGED
|
@@ -240,6 +240,20 @@
|
|
|
240
240
|
"placeholder": "Kapsamdaki uç noktalar veya yüzey"
|
|
241
241
|
}
|
|
242
242
|
},
|
|
243
|
+
"spikeFields": {
|
|
244
|
+
"researchQuestion": {
|
|
245
|
+
"label": "Araştırma sorusu",
|
|
246
|
+
"placeholder": "Spike'ın yanıtlaması gereken soru veya hipotez"
|
|
247
|
+
},
|
|
248
|
+
"successCriteria": {
|
|
249
|
+
"label": "Başarı ölçütleri",
|
|
250
|
+
"placeholder": "Kabul ölçütleri veya bulguların dayanak oluşturması gereken karar"
|
|
251
|
+
},
|
|
252
|
+
"optionsToCompare": {
|
|
253
|
+
"label": "Karşılaştırılacak seçenekler",
|
|
254
|
+
"placeholder": "Birbirine karşı tartılacak seçenekler"
|
|
255
|
+
}
|
|
256
|
+
},
|
|
243
257
|
"optional": "isteğe bağlı",
|
|
244
258
|
"pipeline": "İşlem hattı",
|
|
245
259
|
"chooseAtRunTime": "Çalıştırma sırasında seç",
|
package/i18n/locales/uk.json
CHANGED
|
@@ -240,6 +240,20 @@
|
|
|
240
240
|
"placeholder": "Кінцеві точки або поверхня в межах обсягу"
|
|
241
241
|
}
|
|
242
242
|
},
|
|
243
|
+
"spikeFields": {
|
|
244
|
+
"researchQuestion": {
|
|
245
|
+
"label": "Дослідницьке питання",
|
|
246
|
+
"placeholder": "Питання або гіпотеза, на які має відповісти спайк"
|
|
247
|
+
},
|
|
248
|
+
"successCriteria": {
|
|
249
|
+
"label": "Критерії успіху",
|
|
250
|
+
"placeholder": "Критерії приймання або рішення, яке мають обґрунтувати висновки"
|
|
251
|
+
},
|
|
252
|
+
"optionsToCompare": {
|
|
253
|
+
"label": "Опції для порівняння",
|
|
254
|
+
"placeholder": "Опції, які слід зважити одна проти одної"
|
|
255
|
+
}
|
|
256
|
+
},
|
|
243
257
|
"optional": "необов’язково",
|
|
244
258
|
"pipeline": "Конвеєр",
|
|
245
259
|
"chooseAtRunTime": "Обрати під час запуску",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cat-factory/app",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.120.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.134.0"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@toad-contracts/testing": "0.3.2",
|