@cat-factory/app 0.82.2 → 0.83.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.
@@ -0,0 +1,189 @@
1
+ <script setup lang="ts">
2
+ // The interactive-planning Q&A window (slice 2) — the dedicated view of the initiative
3
+ // INTERVIEWER gate. While the planning run is parked, the interviewer's clarifying questions
4
+ // (pending `qa` entries with an empty answer) are shown here; the human answers them, then
5
+ // either CONTINUES (the interviewer re-runs and may ask follow-ups) or PROCEEDS (skip
6
+ // remaining questions — the interviewer converges and the run advances to the analyst/planner).
7
+ // Opened via the universal result-view host: from the inspector / card
8
+ // (`ui.openInitiativePlanning`) or as the interviewer step's result view. Live `initiative`
9
+ // stream events patch the store, so an open window follows the interview as it progresses.
10
+ import { computed, reactive, watch } from 'vue'
11
+ import { INITIATIVE_STATUS_LABEL_KEYS } from '~/utils/initiative'
12
+
13
+ const board = useBoardStore()
14
+ const initiatives = useInitiativesStore()
15
+ const { t } = useI18n()
16
+
17
+ const { open, blockId, close } = useResultView('initiative-planning', {
18
+ onOpen: (id) => void initiatives.load(id),
19
+ })
20
+
21
+ const block = computed(() => (blockId.value ? board.getBlock(blockId.value) : undefined))
22
+ const initiative = computed(() => (blockId.value ? initiatives.forBlock(blockId.value) : null))
23
+
24
+ /** Every interview exchange, with a stable key for the list + draft map. */
25
+ const questions = computed(() =>
26
+ (initiative.value?.qa ?? []).map((q, i) => ({ ...q, key: q.id ?? `q-${i}` })),
27
+ )
28
+ const pending = computed(() => questions.value.filter((q) => !(q.answer ?? '').trim()))
29
+ /** The interview converged (or never started with a model): nothing left to answer. */
30
+ const converged = computed(() => initiative.value?.interview?.status === 'done')
31
+
32
+ // Per-question answer drafts, seeded from the entity and refreshed as new rounds arrive
33
+ // without clobbering an answer the human is mid-edit on.
34
+ const drafts = reactive<Record<string, string>>({})
35
+ watch(
36
+ questions,
37
+ (list) => {
38
+ for (const q of list) {
39
+ if (!(q.key in drafts)) drafts[q.key] = q.answer ?? ''
40
+ }
41
+ },
42
+ { immediate: true },
43
+ )
44
+
45
+ const resuming = computed(() => initiatives.resuming)
46
+ /** Continue is meaningful once every pending question has a drafted answer. */
47
+ const allAnswered = computed(() => pending.value.every((q) => drafts[q.key]?.trim()))
48
+
49
+ /** Persist one answer if its draft differs from what's recorded. */
50
+ async function persist(q: { id?: string; key: string; answer?: string }) {
51
+ const id = q.id
52
+ if (!id || !blockId.value) return
53
+ const next = (drafts[q.key] ?? '').trim()
54
+ if (!next || next === (q.answer ?? '').trim()) return
55
+ await initiatives.answerQuestion(blockId.value, id, next)
56
+ }
57
+
58
+ /** Flush all dirty drafts, then run a window action (continue / proceed). */
59
+ async function flushThen(action: (id: string) => Promise<unknown>) {
60
+ if (!blockId.value) return
61
+ for (const q of questions.value) await persist(q)
62
+ await action(blockId.value)
63
+ }
64
+
65
+ const onContinue = () => flushThen((id) => initiatives.continuePlanning(id))
66
+ const onProceed = () => flushThen((id) => initiatives.proceedPlanning(id))
67
+ </script>
68
+
69
+ <template>
70
+ <Teleport to="body">
71
+ <div
72
+ v-if="open"
73
+ class="fixed inset-0 z-50 flex max-h-[100dvh] items-stretch justify-center bg-slate-950/70 backdrop-blur-sm"
74
+ @click.self="close"
75
+ >
76
+ <div
77
+ class="m-4 flex w-full max-w-3xl flex-col overflow-hidden rounded-2xl border border-slate-800 bg-slate-900 shadow-2xl"
78
+ role="dialog"
79
+ aria-modal="true"
80
+ data-testid="initiative-planning-window"
81
+ >
82
+ <!-- Header -->
83
+ <header class="flex items-center gap-3 border-b border-slate-800 px-5 py-3">
84
+ <span
85
+ class="flex h-8 w-8 items-center justify-center rounded-lg bg-indigo-500/15 text-indigo-300"
86
+ >
87
+ <UIcon name="i-lucide-messages-square" class="h-4 w-4" />
88
+ </span>
89
+ <div class="min-w-0 flex-1">
90
+ <h2 class="truncate text-sm font-semibold text-slate-100">
91
+ {{ initiative?.title ?? block?.title ?? t('initiative.planning.title') }}
92
+ </h2>
93
+ <p class="truncate text-[11px] text-slate-400">
94
+ {{ t('initiative.planning.subtitle') }}
95
+ </p>
96
+ </div>
97
+ <UBadge v-if="initiative" color="primary" variant="subtle" size="sm">
98
+ {{ t(INITIATIVE_STATUS_LABEL_KEYS[initiative.status]) }}
99
+ </UBadge>
100
+ <button
101
+ class="rounded-md p-1.5 text-slate-400 hover:bg-slate-800 hover:text-slate-200"
102
+ @click="close"
103
+ >
104
+ <UIcon name="i-lucide-x" class="h-4 w-4" />
105
+ </button>
106
+ </header>
107
+
108
+ <div class="min-h-0 flex-1 overflow-y-auto px-5 py-4">
109
+ <!-- No entity yet -->
110
+ <div
111
+ v-if="!initiative"
112
+ class="flex h-full flex-col items-center justify-center gap-2 text-center text-slate-400"
113
+ >
114
+ <UIcon name="i-lucide-messages-square" class="h-8 w-8 opacity-40" />
115
+ <p class="text-sm">{{ t('initiative.planning.empty') }}</p>
116
+ </div>
117
+
118
+ <template v-else>
119
+ <p class="mb-4 text-[13px] leading-relaxed text-slate-300">
120
+ {{ t('initiative.planning.intro') }}
121
+ </p>
122
+
123
+ <!-- Converged / no pending questions -->
124
+ <div
125
+ v-if="converged || questions.length === 0"
126
+ class="rounded-lg border border-slate-800 bg-slate-950/40 p-4 text-center text-[13px] text-slate-400"
127
+ data-testid="initiative-planning-converged"
128
+ >
129
+ {{ t('initiative.planning.converged') }}
130
+ </div>
131
+
132
+ <!-- Interview questions -->
133
+ <ul v-else class="space-y-4">
134
+ <li
135
+ v-for="q in questions"
136
+ :key="q.key"
137
+ class="rounded-lg border border-slate-800 bg-slate-950/40 p-3"
138
+ data-testid="initiative-planning-question"
139
+ >
140
+ <p class="mb-2 text-[13px] font-medium text-slate-200">{{ q.question }}</p>
141
+ <UTextarea
142
+ v-model="drafts[q.key]"
143
+ :rows="2"
144
+ autoresize
145
+ :placeholder="t('initiative.planning.answerPlaceholder')"
146
+ class="w-full"
147
+ data-testid="initiative-planning-answer"
148
+ @blur="persist(q)"
149
+ />
150
+ </li>
151
+ </ul>
152
+ </template>
153
+ </div>
154
+
155
+ <!-- Action rail -->
156
+ <footer
157
+ v-if="initiative && !converged && questions.length > 0"
158
+ class="flex items-center justify-between gap-3 border-t border-slate-800 px-5 py-3"
159
+ >
160
+ <p class="text-[11px] text-slate-500">
161
+ {{ t('initiative.planning.hint') }}
162
+ </p>
163
+ <div class="flex items-center gap-2">
164
+ <UButton
165
+ color="neutral"
166
+ variant="ghost"
167
+ size="sm"
168
+ :loading="resuming"
169
+ data-testid="initiative-planning-proceed"
170
+ @click="onProceed"
171
+ >
172
+ {{ t('initiative.planning.proceed') }}
173
+ </UButton>
174
+ <UButton
175
+ color="primary"
176
+ size="sm"
177
+ :loading="resuming"
178
+ :disabled="!allAnswered"
179
+ data-testid="initiative-planning-continue"
180
+ @click="onContinue"
181
+ >
182
+ {{ t('initiative.planning.continue') }}
183
+ </UButton>
184
+ </div>
185
+ </footer>
186
+ </div>
187
+ </div>
188
+ </Teleport>
189
+ </template>
@@ -24,6 +24,7 @@ import ServiceSpecWindow from '~/components/spec/ServiceSpecWindow.vue'
24
24
  import FollowUpWindow from '~/components/followUp/FollowUpWindow.vue'
25
25
  import MergerResultView from '~/components/panels/MergerResultView.vue'
26
26
  import InitiativeTrackerWindow from '~/components/initiative/InitiativeTrackerWindow.vue'
27
+ import InitiativePlanningWindow from '~/components/initiative/InitiativePlanningWindow.vue'
27
28
 
28
29
  const ui = useUiStore()
29
30
 
@@ -57,6 +58,7 @@ const STEP_RESULT_VIEWS: Record<string, Component> = {
57
58
  // caveats. Opened from the initiative card / inspector (`ui.openInitiativeTracker`) and
58
59
  // as the planner step's result view.
59
60
  'initiative-tracker': InitiativeTrackerWindow,
61
+ 'initiative-planning': InitiativePlanningWindow,
60
62
  }
61
63
 
62
64
  const active = computed<Component | null>(() => {
@@ -22,12 +22,22 @@ const status = computed<InitiativeStatus>(() => initiative.value?.status ?? 'pla
22
22
  const planningPipeline = computed(() => pipelines.pipelines.find((p) => p.id === 'pl_initiative'))
23
23
  const running = computed(() => !!props.block.executionId)
24
24
 
25
+ // The interviewer has parked the planning run with questions awaiting answers.
26
+ const awaitingAnswers = computed(
27
+ () =>
28
+ initiative.value?.interview?.status === 'awaiting' &&
29
+ (initiative.value?.qa ?? []).some((q) => !(q.answer ?? '').trim()),
30
+ )
31
+
25
32
  function runPlanning() {
26
33
  if (planningPipeline.value) void execution.start(props.block.id, planningPipeline.value)
27
34
  }
28
35
  function openTracker() {
29
36
  ui.openInitiativeTracker(props.block.id)
30
37
  }
38
+ function openPlanning() {
39
+ ui.openInitiativePlanning(props.block.id)
40
+ }
31
41
 
32
42
  const progress = computed(() => initiativeProgress(initiative.value?.items))
33
43
  </script>
@@ -48,6 +58,17 @@ const progress = computed(() => initiativeProgress(initiative.value?.items))
48
58
  </p>
49
59
 
50
60
  <div class="flex flex-wrap items-center gap-2">
61
+ <UButton
62
+ v-if="awaitingAnswers"
63
+ data-testid="initiative-answer-planning"
64
+ color="primary"
65
+ variant="solid"
66
+ size="sm"
67
+ icon="i-lucide-messages-square"
68
+ @click="openPlanning"
69
+ >
70
+ {{ t('initiative.inspector.answerPlanning') }}
71
+ </UButton>
51
72
  <UButton
52
73
  data-testid="initiative-run-planning"
53
74
  color="primary"
@@ -1,8 +1,11 @@
1
1
  import {
2
+ answerInitiativeQuestionContract,
3
+ continueInitiativePlanningContract,
2
4
  createInitiativeContract,
3
5
  getInitiativeByBlockContract,
4
6
  getInitiativeContract,
5
7
  listInitiativesContract,
8
+ proceedInitiativePlanningContract,
6
9
  } from '@cat-factory/contracts'
7
10
  import type { ApiContext } from './context'
8
11
 
@@ -24,5 +27,31 @@ export function initiativeApi({ send, ws }: ApiContext) {
24
27
  // The tracker window's load path: the initiative anchored to a board block.
25
28
  getInitiativeByBlock: (workspaceId: string, blockId: string) =>
26
29
  send(getInitiativeByBlockContract, { pathPrefix: ws(workspaceId), pathParams: { blockId } }),
30
+
31
+ // Interactive planning (slice 2): answer one interview question (no run resume), then
32
+ // continue (interviewer re-runs, may ask more) or proceed (skip remaining, plan now).
33
+ answerInitiativeQuestion: (
34
+ workspaceId: string,
35
+ blockId: string,
36
+ questionId: string,
37
+ answer: string,
38
+ ) =>
39
+ send(answerInitiativeQuestionContract, {
40
+ pathPrefix: ws(workspaceId),
41
+ pathParams: { blockId },
42
+ body: { questionId, answer },
43
+ }),
44
+
45
+ continueInitiativePlanning: (workspaceId: string, blockId: string) =>
46
+ send(continueInitiativePlanningContract, {
47
+ pathPrefix: ws(workspaceId),
48
+ pathParams: { blockId },
49
+ }),
50
+
51
+ proceedInitiativePlanning: (workspaceId: string, blockId: string) =>
52
+ send(proceedInitiativePlanningContract, {
53
+ pathPrefix: ws(workspaceId),
54
+ pathParams: { blockId },
55
+ }),
27
56
  }
28
57
  }
@@ -90,9 +90,66 @@ export const useInitiativesStore = defineStore('initiatives', () => {
90
90
  }
91
91
  }
92
92
 
93
+ /** True while a planning-window action (continue/proceed) is resuming the run. */
94
+ const resuming = ref(false)
95
+
96
+ /** Record the human's answer to one pending interview question (no run resume). */
97
+ async function answerQuestion(blockId: string, questionId: string, answer: string) {
98
+ if (!workspace.workspaceId) throw new Error('No active workspace')
99
+ const updated = await api.answerInitiativeQuestion(
100
+ workspace.workspaceId,
101
+ blockId,
102
+ questionId,
103
+ answer,
104
+ )
105
+ upsert(updated)
106
+ return updated
107
+ }
108
+
109
+ /** Submit the answers and resume the interview (the interviewer re-runs, may ask more). */
110
+ async function continuePlanning(blockId: string) {
111
+ if (!workspace.workspaceId) throw new Error('No active workspace')
112
+ resuming.value = true
113
+ try {
114
+ const updated = await api.continueInitiativePlanning(workspace.workspaceId, blockId)
115
+ upsert(updated)
116
+ return updated
117
+ } finally {
118
+ resuming.value = false
119
+ }
120
+ }
121
+
122
+ /** Skip remaining questions: the interviewer converges and the run advances. */
123
+ async function proceedPlanning(blockId: string) {
124
+ if (!workspace.workspaceId) throw new Error('No active workspace')
125
+ resuming.value = true
126
+ try {
127
+ const updated = await api.proceedInitiativePlanning(workspace.workspaceId, blockId)
128
+ upsert(updated)
129
+ return updated
130
+ } finally {
131
+ resuming.value = false
132
+ }
133
+ }
134
+
93
135
  function reset() {
94
136
  byBlock.value = {}
95
137
  }
96
138
 
97
- return { available, byBlock, all, creating, forBlock, hydrate, upsert, create, load, reset }
139
+ return {
140
+ available,
141
+ byBlock,
142
+ all,
143
+ creating,
144
+ resuming,
145
+ forBlock,
146
+ hydrate,
147
+ upsert,
148
+ create,
149
+ load,
150
+ answerQuestion,
151
+ continuePlanning,
152
+ proceedPlanning,
153
+ reset,
154
+ }
98
155
  })
package/app/stores/ui.ts CHANGED
@@ -728,6 +728,11 @@ export const useUiStore = defineStore('ui', () => {
728
728
  function openInitiativeTracker(blockId: string) {
729
729
  resultView.value = { view: 'initiative-tracker', blockId, instanceId: null, stepIndex: null }
730
730
  }
731
+ // Open the interactive-planning Q&A window for an initiative block (inspector / card,
732
+ // when the interviewer has parked the planning run with pending questions).
733
+ function openInitiativePlanning(blockId: string) {
734
+ resultView.value = { view: 'initiative-planning', blockId, instanceId: null, stepIndex: null }
735
+ }
731
736
  // Open the Follow-up companion window for a run's Coder step (the blinking chip + the
732
737
  // `followup_pending` notification). Resolves the Coder step index from the run when not
733
738
  // given, so callers that only know the run can still open it.
@@ -939,6 +944,7 @@ export const useUiStore = defineStore('ui', () => {
939
944
  openBrainstorm,
940
945
  openServiceSpec,
941
946
  openInitiativeTracker,
947
+ openInitiativePlanning,
942
948
  openFollowUps,
943
949
  closeRequirementReview,
944
950
  openStepDetail,
@@ -347,6 +347,25 @@ export const SYSTEM_AGENT_META: Record<string, AgentArchetype> = {
347
347
  // The Initiative Planning pipeline's two steps. Only runnable on an initiative
348
348
  // block (pl_initiative — enforced by the engine), so they are display-metadata
349
349
  // system kinds, never palette archetypes.
350
+ 'initiative-interviewer': {
351
+ kind: 'initiative-interviewer',
352
+ label: 'Initiative Interviewer',
353
+ icon: 'i-lucide-messages-square',
354
+ color: '#818cf8',
355
+ description:
356
+ 'Interviews you on the goals, scope and constraints of the initiative, then synthesizes the agreed brief the analyst and planner build on.',
357
+ // Opens the dedicated planning Q&A window (answer / continue / proceed) while parked.
358
+ resultView: 'initiative-planning',
359
+ },
360
+ 'initiative-analyst': {
361
+ kind: 'initiative-analyst',
362
+ label: 'Initiative Analyst',
363
+ icon: 'i-lucide-microscope',
364
+ color: '#818cf8',
365
+ description:
366
+ 'Explores the codebase and writes an analysis (architecture, touch points, risks) that grounds the plan. Makes no changes.',
367
+ resultView: 'initiative-tracker',
368
+ },
350
369
  'initiative-planner': {
351
370
  kind: 'initiative-planner',
352
371
  label: 'Initiative Planner',
@@ -4139,7 +4139,19 @@
4139
4139
  },
4140
4140
  "inspector": {
4141
4141
  "runPlanning": "Run planning",
4142
+ "answerPlanning": "Answer planning questions",
4142
4143
  "hint": "The planning pipeline explores the codebase, drafts the multi-phase plan for approval, then commits the tracker document to the repository."
4144
+ },
4145
+ "planning": {
4146
+ "title": "Plan the initiative",
4147
+ "subtitle": "Answer the planner's questions so it can scope the initiative",
4148
+ "intro": "The planner is scoping this initiative. Answer its questions to shape the goal and constraints, then continue — or proceed to plan with what it has.",
4149
+ "empty": "No initiative found for this block.",
4150
+ "converged": "No questions are pending. The planner has what it needs and is drafting the plan.",
4151
+ "answerPlaceholder": "Your answer",
4152
+ "hint": "Continue lets the planner ask follow-ups; Proceed plans with the answers so far.",
4153
+ "proceed": "Proceed to plan",
4154
+ "continue": "Continue"
4143
4155
  }
4144
4156
  }
4145
4157
  }
@@ -4020,7 +4020,19 @@
4020
4020
  },
4021
4021
  "inspector": {
4022
4022
  "runPlanning": "Ejecutar planificacion",
4023
+ "answerPlanning": "Responder preguntas de planificacion",
4023
4024
  "hint": "El pipeline de planificacion explora el codigo, redacta el plan multifase para su aprobacion y luego confirma el documento de seguimiento en el repositorio."
4025
+ },
4026
+ "planning": {
4027
+ "title": "Planificar la iniciativa",
4028
+ "subtitle": "Responde las preguntas del planificador para acotar la iniciativa",
4029
+ "intro": "El planificador esta acotando esta iniciativa. Responde sus preguntas para definir el objetivo y las restricciones, luego continua, o procede a planificar con lo que tiene.",
4030
+ "empty": "No se encontro ninguna iniciativa para este bloque.",
4031
+ "converged": "No hay preguntas pendientes. El planificador tiene lo que necesita y esta redactando el plan.",
4032
+ "answerPlaceholder": "Tu respuesta",
4033
+ "hint": "Continuar permite al planificador hacer mas preguntas; Proceder planifica con las respuestas actuales.",
4034
+ "proceed": "Proceder a planificar",
4035
+ "continue": "Continuar"
4024
4036
  }
4025
4037
  }
4026
4038
  }
@@ -4020,7 +4020,19 @@
4020
4020
  },
4021
4021
  "inspector": {
4022
4022
  "runPlanning": "Lancer la planification",
4023
+ "answerPlanning": "Repondre aux questions de planification",
4023
4024
  "hint": "Le pipeline de planification explore le code, redige le plan multiphase pour approbation, puis valide le document de suivi dans le depot."
4025
+ },
4026
+ "planning": {
4027
+ "title": "Planifier l'initiative",
4028
+ "subtitle": "Repondez aux questions du planificateur pour cadrer l'initiative",
4029
+ "intro": "Le planificateur cadre cette initiative. Repondez a ses questions pour definir l'objectif et les contraintes, puis continuez, ou procedez a la planification avec ce qu'il a.",
4030
+ "empty": "Aucune initiative trouvee pour ce bloc.",
4031
+ "converged": "Aucune question en attente. Le planificateur dispose de ce qu'il faut et redige le plan.",
4032
+ "answerPlaceholder": "Votre reponse",
4033
+ "hint": "Continuer permet au planificateur de poser des questions complementaires ; Proceder planifie avec les reponses actuelles.",
4034
+ "proceed": "Proceder a la planification",
4035
+ "continue": "Continuer"
4024
4036
  }
4025
4037
  }
4026
4038
  }
@@ -4031,7 +4031,19 @@
4031
4031
  },
4032
4032
  "inspector": {
4033
4033
  "runPlanning": "הרצת תכנון",
4034
+ "answerPlanning": "מענה על שאלות התכנון",
4034
4035
  "hint": "צינור התכנון חוקר את הקוד, מנסח את התוכנית הרב-שלבית לאישור, ואז שומר את מסמך המעקב במאגר."
4036
+ },
4037
+ "planning": {
4038
+ "title": "תכנון היוזמה",
4039
+ "subtitle": "ענה על שאלות המתכנן כדי למקד את היוזמה",
4040
+ "intro": "המתכנן ממקד את היוזמה. ענה על שאלותיו כדי לעצב את המטרה והאילוצים, ואז המשך — או עבור לתכנון עם מה שיש לו.",
4041
+ "empty": "לא נמצאה יוזמה עבור בלוק זה.",
4042
+ "converged": "אין שאלות ממתינות. למתכנן יש את מה שנדרש והוא מנסח את התוכנית.",
4043
+ "answerPlaceholder": "התשובה שלך",
4044
+ "hint": "המשך מאפשר למתכנן לשאול שאלות המשך; עבור לתכנון מתכנן עם התשובות עד כה.",
4045
+ "proceed": "עבור לתכנון",
4046
+ "continue": "המשך"
4035
4047
  }
4036
4048
  }
4037
4049
  }
@@ -4033,7 +4033,19 @@
4033
4033
  },
4034
4034
  "inspector": {
4035
4035
  "runPlanning": "計画を実行",
4036
+ "answerPlanning": "計画の質問に回答",
4036
4037
  "hint": "計画パイプラインはコードベースを調査し、承認用の複数フェーズ計画を起草し、その後トラッカー文書をリポジトリにコミットします。"
4038
+ },
4039
+ "planning": {
4040
+ "title": "イニシアチブを計画",
4041
+ "subtitle": "プランナーの質問に答えてイニシアチブの範囲を定めます",
4042
+ "intro": "プランナーがこのイニシアチブの範囲を検討しています。質問に答えて目標と制約を形にし、続行するか、現状のまま計画に進んでください。",
4043
+ "empty": "このブロックのイニシアチブが見つかりません。",
4044
+ "converged": "保留中の質問はありません。プランナーは必要な情報を得て計画を作成しています。",
4045
+ "answerPlaceholder": "回答",
4046
+ "hint": "「続行」でプランナーが追加の質問をします。「計画に進む」でこれまでの回答をもとに計画します。",
4047
+ "proceed": "計画に進む",
4048
+ "continue": "続行"
4037
4049
  }
4038
4050
  }
4039
4051
  }
@@ -4020,7 +4020,19 @@
4020
4020
  },
4021
4021
  "inspector": {
4022
4022
  "runPlanning": "Uruchom planowanie",
4023
+ "answerPlanning": "Odpowiedz na pytania planowania",
4023
4024
  "hint": "Pipeline planowania bada kod, przygotowuje wielofazowy plan do zatwierdzenia, a nastepnie zapisuje dokument trackera w repozytorium."
4025
+ },
4026
+ "planning": {
4027
+ "title": "Zaplanuj inicjatywe",
4028
+ "subtitle": "Odpowiedz na pytania planisty, aby okreslic zakres inicjatywy",
4029
+ "intro": "Planista okresla zakres tej inicjatywy. Odpowiedz na pytania, aby uksztaltowac cel i ograniczenia, a nastepnie kontynuuj lub przejdz do planowania z tym, co ma.",
4030
+ "empty": "Nie znaleziono inicjatywy dla tego bloku.",
4031
+ "converged": "Brak oczekujacych pytan. Planista ma to, czego potrzebuje, i tworzy plan.",
4032
+ "answerPlaceholder": "Twoja odpowiedz",
4033
+ "hint": "Kontynuuj pozwala planiscie zadac kolejne pytania; Przejdz do planowania planuje na podstawie dotychczasowych odpowiedzi.",
4034
+ "proceed": "Przejdz do planowania",
4035
+ "continue": "Kontynuuj"
4024
4036
  }
4025
4037
  }
4026
4038
  }
@@ -4033,7 +4033,19 @@
4033
4033
  },
4034
4034
  "inspector": {
4035
4035
  "runPlanning": "Planlamayi calistir",
4036
+ "answerPlanning": "Planlama sorularini yanitla",
4036
4037
  "hint": "Planlama hatti kod tabanini inceler, onay icin cok asamali plani hazirlar ve ardindan izleyici belgesini depoya kaydeder."
4038
+ },
4039
+ "planning": {
4040
+ "title": "Girisimi planla",
4041
+ "subtitle": "Girisimi kapsamlandirmak icin planlayicinin sorularini yanitlayin",
4042
+ "intro": "Planlayici bu girisimi kapsamlandiriyor. Hedefi ve kisitlari sekillendirmek icin sorularini yanitlayin, ardindan devam edin veya elindekiyle planlamaya gecin.",
4043
+ "empty": "Bu blok icin girisim bulunamadi.",
4044
+ "converged": "Bekleyen soru yok. Planlayici ihtiyaci olani aldi ve plani hazirliyor.",
4045
+ "answerPlaceholder": "Yanitiniz",
4046
+ "hint": "Devam et, planlayicinin ek sorular sormasini saglar; Planlamaya gec, mevcut yanitlarla planlar.",
4047
+ "proceed": "Planlamaya gec",
4048
+ "continue": "Devam et"
4037
4049
  }
4038
4050
  }
4039
4051
  }
@@ -4020,7 +4020,19 @@
4020
4020
  },
4021
4021
  "inspector": {
4022
4022
  "runPlanning": "Запустити планування",
4023
+ "answerPlanning": "Відповісти на питання планування",
4023
4024
  "hint": "Пайплайн планування досліджує кодову базу, готує багатофазний план на затвердження, а потім комітить документ трекера до репозиторію."
4025
+ },
4026
+ "planning": {
4027
+ "title": "Спланувати ініціативу",
4028
+ "subtitle": "Дайте відповіді на питання планувальника, щоб окреслити ініціативу",
4029
+ "intro": "Планувальник окреслює цю ініціативу. Дайте відповіді на його питання, щоб сформувати мету й обмеження, а потім продовжте — або перейдіть до планування з наявними відповідями.",
4030
+ "empty": "Для цього блоку ініціативу не знайдено.",
4031
+ "converged": "Немає питань, що очікують. Планувальник має все необхідне й готує план.",
4032
+ "answerPlaceholder": "Ваша відповідь",
4033
+ "hint": "Продовжити дозволяє планувальнику ставити додаткові питання; Перейти до планування планує з наявними відповідями.",
4034
+ "proceed": "Перейти до планування",
4035
+ "continue": "Продовжити"
4024
4036
  }
4025
4037
  }
4026
4038
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cat-factory/app",
3
- "version": "0.82.2",
3
+ "version": "0.83.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.88.0"
37
+ "@cat-factory/contracts": "0.89.0"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@toad-contracts/testing": "0.3.2",