@cat-factory/app 0.83.1 → 0.85.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.
@@ -32,6 +32,9 @@ const description = ref('')
32
32
  const pipelineId = ref('')
33
33
  const saving = ref(false)
34
34
  const recurrence = ref<Recurrence>(defaultRecurrence())
35
+ // On-demand: no cadence, fires only via "run now". Because a person is present at fire time,
36
+ // its block may use an individual-usage subscription model (which a cadence schedule can't).
37
+ const onDemand = ref(false)
35
38
 
36
39
  // Tracker config (only relevant when the tech-debt pipeline is picked).
37
40
  const trackerKind = ref<'github' | 'jira' | 'linear' | null>(null)
@@ -83,6 +86,7 @@ watch(open, (isOpen) => {
83
86
  pipelines.pipelines[0]?.id ??
84
87
  ''
85
88
  recurrence.value = defaultRecurrence()
89
+ onDemand.value = false
86
90
  saving.value = false
87
91
  trackerKind.value = tracker.settings.tracker
88
92
  jiraProjectKey.value = tracker.settings.jiraProjectKey ?? ''
@@ -110,7 +114,9 @@ async function add() {
110
114
  pipelineId: pipelineId.value,
111
115
  template: template.value,
112
116
  name: name.value.trim(),
113
- recurrence: recurrence.value,
117
+ // An on-demand schedule carries no cadence; a scheduled one sends its recurrence.
118
+ onDemand: onDemand.value,
119
+ ...(onDemand.value ? {} : { recurrence: recurrence.value }),
114
120
  ...(description.value.trim() ? { description: description.value.trim() } : {}),
115
121
  })
116
122
  ui.closeAddRecurring()
@@ -173,7 +179,15 @@ async function add() {
173
179
  />
174
180
  </UFormField>
175
181
 
176
- <RecurringRecurrenceEditor v-model="recurrence" />
182
+ <div class="flex items-start gap-2 rounded-lg border border-slate-800 p-3">
183
+ <USwitch v-model="onDemand" size="sm" class="mt-0.5" />
184
+ <div class="space-y-0.5">
185
+ <p class="text-xs font-medium text-slate-200">{{ t('board.recurring.onDemand') }}</p>
186
+ <p class="text-[11px] text-slate-500">{{ t('board.recurring.onDemandHint') }}</p>
187
+ </div>
188
+ </div>
189
+
190
+ <RecurringRecurrenceEditor v-if="!onDemand" v-model="recurrence" />
177
191
 
178
192
  <div v-if="isTechDebt" class="space-y-3 rounded-lg border border-slate-800 p-3">
179
193
  <p class="text-[11px] font-semibold uppercase tracking-wide text-slate-400">
@@ -13,6 +13,7 @@ import {
13
13
  INITIATIVE_ITEM_STATUS_CHIPS,
14
14
  INITIATIVE_ITEM_STATUS_LABEL_KEYS,
15
15
  INITIATIVE_STATUS_LABEL_KEYS,
16
+ initiativeProgress,
16
17
  } from '~/utils/initiative'
17
18
 
18
19
  const board = useBoardStore()
@@ -31,6 +32,13 @@ function itemsOf(phaseId: string): InitiativeItem[] {
31
32
  return (initiative.value?.items ?? []).filter((i) => i.phaseId === phaseId)
32
33
  }
33
34
 
35
+ const progress = computed(() => initiativeProgress(initiative.value?.items))
36
+ const progressPct = computed(() =>
37
+ progress.value && progress.value.total > 0
38
+ ? Math.round((progress.value.settled / progress.value.total) * 100)
39
+ : 0,
40
+ )
41
+
34
42
  const policyRules = computed(() => initiative.value?.policy?.rules ?? [])
35
43
  function ruleAxes(rule: { minComplexity?: number; minRisk?: number; minImpact?: number }): string {
36
44
  const axes = [
@@ -74,6 +82,17 @@ function ruleAxes(rule: { minComplexity?: number; minRisk?: number; minImpact?:
74
82
  {{ t('initiative.tracker.subtitle') }}
75
83
  </p>
76
84
  </div>
85
+ <div v-if="progress" class="flex items-center gap-2" data-testid="initiative-progress">
86
+ <div class="h-1.5 w-24 overflow-hidden rounded-full bg-slate-800">
87
+ <div
88
+ class="h-full rounded-full bg-emerald-500 transition-[width] duration-500"
89
+ :style="{ width: `${progressPct}%` }"
90
+ />
91
+ </div>
92
+ <span class="text-[11px] tabular-nums text-slate-400">
93
+ {{ t('initiative.card.progress', { done: progress.settled, total: progress.total }) }}
94
+ </span>
95
+ </div>
77
96
  <UBadge v-if="initiative" color="primary" variant="subtle" size="sm">
78
97
  {{ t(INITIATIVE_STATUS_LABEL_KEYS[initiative.status]) }}
79
98
  </UBadge>
@@ -60,6 +60,9 @@ const META: Record<Notification['type'], { icon: string; color: Accent }> = {
60
60
  // Clicking the title opens the Follow-up companion window for the run (see `reveal`); "act"
61
61
  // just marks it read (items are decided in that window — file / send back / answer — not here).
62
62
  followup_pending: { icon: 'i-lucide-compass', color: 'warning' },
63
+ // The initiative loop needs attention (a blocked task, or completion). Clicking the title
64
+ // opens the initiative tracker window; "act" just marks it read.
65
+ initiative: { icon: 'i-lucide-milestone', color: 'primary' },
63
66
  }
64
67
 
65
68
  // Per-type primary-action label. An exhaustive Record keyed off the notification
@@ -78,6 +81,7 @@ const ACTION_KEYS: Record<Notification['type'], string> = {
78
81
  visual_confirmation_ready: 'layout.notifications.action.visual_confirmation_ready',
79
82
  human_review: 'layout.notifications.action.human_review',
80
83
  followup_pending: 'layout.notifications.action.followup_pending',
84
+ initiative: 'layout.notifications.action.initiative',
81
85
  }
82
86
 
83
87
  /** The localized primary-action label for a notification (te()-guarded against a
@@ -147,6 +151,7 @@ function reveal(n: Notification) {
147
151
  else if (n.type === 'visual_confirmation_ready') revealVisualConfirm(n)
148
152
  else if (n.type === 'human_review') revealHumanReview(n)
149
153
  else if (n.type === 'followup_pending') revealFollowUps(n)
154
+ else if (n.type === 'initiative') ui.openInitiativeTracker(n.blockId)
150
155
  else ui.select(n.blockId)
151
156
  }
152
157
 
@@ -1,8 +1,9 @@
1
1
  <script setup lang="ts">
2
2
  // Inspector body for an `initiative`-level block: the entity's status + goal, the
3
3
  // "Run planning" control (pinned to the Initiative Planning pipeline — the engine
4
- // refuses any other on this block), and the tracker window opener. Read-only in
5
- // this slice; plan/policy editing lands with the execution loop.
4
+ // refuses any other on this block), the execution-loop controls (pause / resume /
5
+ // cancel once executing), and the tracker window opener. Plan/policy editing lands
6
+ // with slice 4.
6
7
  import type { Block, InitiativeStatus } from '~/types/domain'
7
8
  import { INITIATIVE_STATUS_LABEL_KEYS, initiativeProgress } from '~/utils/initiative'
8
9
 
@@ -40,6 +41,13 @@ function openPlanning() {
40
41
  }
41
42
 
42
43
  const progress = computed(() => initiativeProgress(initiative.value?.items))
44
+
45
+ // Execution-loop controls appear once planning is done (the loop owns the block).
46
+ const isExecuting = computed(() => status.value === 'executing')
47
+ const isPaused = computed(() => status.value === 'paused')
48
+ function control(action: 'pause' | 'resume' | 'cancel') {
49
+ void initiatives.control(props.block.id, action)
50
+ }
43
51
  </script>
44
52
 
45
53
  <template>
@@ -92,6 +100,45 @@ const progress = computed(() => initiativeProgress(initiative.value?.items))
92
100
  </UButton>
93
101
  </div>
94
102
 
103
+ <!-- Execution-loop controls (slice 3): pause / resume / cancel an executing initiative. -->
104
+ <div v-if="isExecuting || isPaused" class="flex flex-wrap items-center gap-2">
105
+ <UButton
106
+ v-if="isExecuting"
107
+ data-testid="initiative-pause"
108
+ color="warning"
109
+ variant="soft"
110
+ size="sm"
111
+ icon="i-lucide-pause"
112
+ :loading="initiatives.controlling"
113
+ @click="control('pause')"
114
+ >
115
+ {{ t('initiative.inspector.pause') }}
116
+ </UButton>
117
+ <UButton
118
+ v-if="isPaused"
119
+ data-testid="initiative-resume"
120
+ color="primary"
121
+ variant="soft"
122
+ size="sm"
123
+ icon="i-lucide-play"
124
+ :loading="initiatives.controlling"
125
+ @click="control('resume')"
126
+ >
127
+ {{ t('initiative.inspector.resume') }}
128
+ </UButton>
129
+ <UButton
130
+ data-testid="initiative-cancel"
131
+ color="error"
132
+ variant="soft"
133
+ size="sm"
134
+ icon="i-lucide-square"
135
+ :loading="initiatives.controlling"
136
+ @click="control('cancel')"
137
+ >
138
+ {{ t('initiative.inspector.cancel') }}
139
+ </UButton>
140
+ </div>
141
+
95
142
  <p class="text-[11px] text-slate-500">
96
143
  {{ t('initiative.inspector.hint') }}
97
144
  </p>
@@ -150,8 +150,18 @@ function fmtTime(ms: number) {
150
150
  <UIcon name="i-lucide-repeat" class="h-3.5 w-3.5" />
151
151
  {{ t('inspector.recurring.title') }}
152
152
  </span>
153
- <UBadge :color="schedule.enabled ? 'primary' : 'neutral'" variant="subtle" size="xs">
154
- {{ schedule.enabled ? t('inspector.recurring.active') : t('inspector.recurring.paused') }}
153
+ <UBadge
154
+ :color="schedule.onDemand ? 'primary' : schedule.enabled ? 'primary' : 'neutral'"
155
+ variant="subtle"
156
+ size="xs"
157
+ >
158
+ {{
159
+ schedule.onDemand
160
+ ? t('inspector.recurring.onDemand')
161
+ : schedule.enabled
162
+ ? t('inspector.recurring.active')
163
+ : t('inspector.recurring.paused')
164
+ }}
155
165
  </UBadge>
156
166
  </div>
157
167
 
@@ -159,7 +169,17 @@ function fmtTime(ms: number) {
159
169
  <span class="text-slate-300">{{ pipelineName }}</span>
160
170
  </p>
161
171
 
162
- <template v-if="!editing">
172
+ <!-- On-demand: no cadence, no pause/resume — it fires only when a person triggers it. -->
173
+ <template v-if="schedule.onDemand">
174
+ <p class="text-[11px] text-slate-500">{{ t('inspector.recurring.onDemandHint') }}</p>
175
+ <div class="flex flex-wrap gap-1.5 pt-1">
176
+ <UButton size="xs" variant="soft" icon="i-lucide-play" :loading="busy" @click="runNow">
177
+ {{ t('inspector.recurring.runNow') }}
178
+ </UButton>
179
+ </div>
180
+ </template>
181
+
182
+ <template v-else-if="!editing">
163
183
  <p class="text-[11px] text-slate-400">{{ describeCadence(schedule.recurrence) }}</p>
164
184
  <p class="text-[11px] text-slate-500">
165
185
  {{ t('inspector.recurring.nextRun', { time: fmtTime(schedule.nextRunAt) }) }}
@@ -31,6 +31,7 @@ const ROUTABLE = computed<{ type: NotificationType; label: string }[]>(() => [
31
31
  { type: 'release_regression', label: t('slack.routable.release_regression') },
32
32
  { type: 'human_test_ready', label: t('slack.routable.human_test_ready') },
33
33
  { type: 'visual_confirmation_ready', label: t('slack.routable.visual_confirmation_ready') },
34
+ { type: 'initiative', label: t('slack.routable.initiative') },
34
35
  ])
35
36
 
36
37
  /** Notification-role options for a mapped member (drives who gets @-mentioned). */
@@ -54,6 +55,7 @@ const routes = reactive<Record<NotificationType, SlackRoute>>({
54
55
  visual_confirmation_ready: { enabled: false, channel: '' },
55
56
  human_review: { enabled: false, channel: '' },
56
57
  followup_pending: { enabled: false, channel: '' },
58
+ initiative: { enabled: false, channel: '' },
57
59
  })
58
60
  const mentionsEnabled = ref(false)
59
61
  const mapping = ref<SlackMemberMappingEntry[]>([])
@@ -1,11 +1,14 @@
1
1
  import {
2
2
  answerInitiativeQuestionContract,
3
+ cancelInitiativeContract,
3
4
  continueInitiativePlanningContract,
4
5
  createInitiativeContract,
5
6
  getInitiativeByBlockContract,
6
7
  getInitiativeContract,
7
8
  listInitiativesContract,
9
+ pauseInitiativeContract,
8
10
  proceedInitiativePlanningContract,
11
+ resumeInitiativeContract,
9
12
  } from '@cat-factory/contracts'
10
13
  import type { ApiContext } from './context'
11
14
 
@@ -53,5 +56,15 @@ export function initiativeApi({ send, ws }: ApiContext) {
53
56
  pathPrefix: ws(workspaceId),
54
57
  pathParams: { blockId },
55
58
  }),
59
+
60
+ // Execution-loop controls (slice 3): pause / resume / cancel an executing initiative.
61
+ pauseInitiative: (workspaceId: string, blockId: string) =>
62
+ send(pauseInitiativeContract, { pathPrefix: ws(workspaceId), pathParams: { blockId } }),
63
+
64
+ resumeInitiative: (workspaceId: string, blockId: string) =>
65
+ send(resumeInitiativeContract, { pathPrefix: ws(workspaceId), pathParams: { blockId } }),
66
+
67
+ cancelInitiative: (workspaceId: string, blockId: string) =>
68
+ send(cancelInitiativeContract, { pathPrefix: ws(workspaceId), pathParams: { blockId } }),
56
69
  }
57
70
  }
@@ -21,7 +21,7 @@ import type { ApiContext, Position } from './context'
21
21
  type CreateScheduleBody = NonNullable<SendParams<typeof createScheduleContract>['body']>
22
22
 
23
23
  /** Recurring (scheduled) pipelines + the in-org shared-service mount catalog. */
24
- export function recurringApi({ send, ws }: ApiContext) {
24
+ export function recurringApi({ send, sendWith, ws, pwHeaders }: ApiContext) {
25
25
  return {
26
26
  // ---- recurring pipelines (scheduled runs against a service) -----------
27
27
  listRecurringPipelines: (workspaceId: string) =>
@@ -46,8 +46,13 @@ export function recurringApi({ send, ws }: ApiContext) {
46
46
  pathParams: { scheduleId: id },
47
47
  }),
48
48
 
49
- runScheduleNow: (workspaceId: string, id: string) =>
50
- send(runScheduleNowContract, { pathPrefix: ws(workspaceId), pathParams: { scheduleId: id } }),
49
+ // On-demand schedules may target an individual-usage model, so run-now carries the
50
+ // initiator's personal password (like a manual start) prompted + retried on a 428.
51
+ runScheduleNow: (workspaceId: string, id: string, password?: string) =>
52
+ sendWith(pwHeaders(password), runScheduleNowContract, {
53
+ pathPrefix: ws(workspaceId),
54
+ pathParams: { scheduleId: id },
55
+ }),
51
56
 
52
57
  // ---- in-org shared services (mount/unmount + org catalog) -------------
53
58
  // The services this workspace mounts, and the org catalog it can mount from. A 503
@@ -132,6 +132,28 @@ export const useInitiativesStore = defineStore('initiatives', () => {
132
132
  }
133
133
  }
134
134
 
135
+ /** True while a loop control (pause/resume/cancel) is in flight. */
136
+ const controlling = ref(false)
137
+
138
+ /** Pause / resume / cancel an executing initiative's loop. Applies the returned entity. */
139
+ async function control(blockId: string, action: 'pause' | 'resume' | 'cancel') {
140
+ if (!workspace.workspaceId) throw new Error('No active workspace')
141
+ controlling.value = true
142
+ try {
143
+ const call =
144
+ action === 'pause'
145
+ ? api.pauseInitiative
146
+ : action === 'resume'
147
+ ? api.resumeInitiative
148
+ : api.cancelInitiative
149
+ const updated = await call(workspace.workspaceId, blockId)
150
+ if (updated) upsert(updated)
151
+ return updated
152
+ } finally {
153
+ controlling.value = false
154
+ }
155
+ }
156
+
135
157
  function reset() {
136
158
  byBlock.value = {}
137
159
  }
@@ -142,6 +164,7 @@ export const useInitiativesStore = defineStore('initiatives', () => {
142
164
  all,
143
165
  creating,
144
166
  resuming,
167
+ controlling,
145
168
  forBlock,
146
169
  hydrate,
147
170
  upsert,
@@ -150,6 +173,7 @@ export const useInitiativesStore = defineStore('initiatives', () => {
150
173
  answerQuestion,
151
174
  continuePlanning,
152
175
  proceedPlanning,
176
+ control,
153
177
  reset,
154
178
  }
155
179
  })
@@ -80,12 +80,20 @@ export const useRecurringPipelinesStore = defineStore('recurringPipelines', () =
80
80
  }
81
81
  }
82
82
 
83
- async function runNow(id: string) {
83
+ /**
84
+ * Fire a schedule now. An on-demand schedule may target an individual-usage model, so the
85
+ * initiator's personal password is supplied transparently from the cache and prompted via
86
+ * the credential modal (then retried) when the server replies 428. Returns false when the
87
+ * user cancels the password prompt; true once the fire is accepted.
88
+ */
89
+ async function runNow(id: string): Promise<boolean> {
84
90
  const ws = useWorkspaceStore()
85
- const schedule = await api.runScheduleNow(ws.requireId(), id)
86
- await loadRuns(id)
87
- await ws.refresh()
88
- return schedule
91
+ const personal = usePersonalSubscriptionsStore()
92
+ return personal.withCredential(async (password) => {
93
+ await api.runScheduleNow(ws.requireId(), id, password)
94
+ await loadRuns(id)
95
+ await ws.refresh()
96
+ })
89
97
  }
90
98
 
91
99
  /** Fetch (and cache) a schedule's run history for the inspector. */
@@ -217,7 +217,9 @@
217
217
  "linearTeamId": "Linear team id",
218
218
  "footerHint": "A single recurring task is added inside the service; each run replaces the last. Its run history is visible in the inspector.",
219
219
  "submit": "Add recurring pipeline",
220
- "addFailedTitle": "Could not add recurring pipeline"
220
+ "addFailedTitle": "Could not add recurring pipeline",
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."
221
223
  },
222
224
  "failure": {
223
225
  "containerFailedToStart": "Container failed to start",
@@ -481,7 +483,9 @@
481
483
  "skipped": "Skipped"
482
484
  },
483
485
  "updateFailed": "Could not update schedule",
484
- "runNowFailed": "Could not run now"
486
+ "runNowFailed": "Could not run now",
487
+ "onDemand": "On-demand",
488
+ "onDemandHint": "Manual only. Runs when you trigger it, and may use an individual-usage subscription model."
485
489
  },
486
490
  "fragments": {
487
491
  "serviceTitle": "Service best practices",
@@ -1346,6 +1350,7 @@
1346
1350
  "visual_confirmation_ready": "Mark read",
1347
1351
  "human_review": "Mark read",
1348
1352
  "followup_pending": "Mark read",
1353
+ "initiative": "Mark read",
1349
1354
  "markRead": "Mark read"
1350
1355
  }
1351
1356
  },
@@ -2623,7 +2628,8 @@
2623
2628
  "clarity_review": "Clarity review",
2624
2629
  "release_regression": "Release regression",
2625
2630
  "human_test_ready": "Ready for human testing",
2626
- "visual_confirmation_ready": "Ready for visual confirmation"
2631
+ "visual_confirmation_ready": "Ready for visual confirmation",
2632
+ "initiative": "Initiative updates"
2627
2633
  },
2628
2634
  "role": {
2629
2635
  "engineering": "Engineering",
@@ -4140,6 +4146,9 @@
4140
4146
  "inspector": {
4141
4147
  "runPlanning": "Run planning",
4142
4148
  "answerPlanning": "Answer planning questions",
4149
+ "pause": "Pause",
4150
+ "resume": "Resume",
4151
+ "cancel": "Cancel initiative",
4143
4152
  "hint": "The planning pipeline explores the codebase, drafts the multi-phase plan for approval, then commits the tracker document to the repository."
4144
4153
  },
4145
4154
  "planning": {
@@ -196,7 +196,9 @@
196
196
  "linearTeamId": "ID del equipo de Linear",
197
197
  "footerHint": "Se añade una única tarea recurrente dentro del servicio; cada ejecución reemplaza a la anterior. Su historial de ejecuciones es visible en el inspector.",
198
198
  "submit": "Añadir pipeline recurrente",
199
- "addFailedTitle": "No se pudo añadir la pipeline recurrente"
199
+ "addFailedTitle": "No se pudo añadir la pipeline recurrente",
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."
200
202
  },
201
203
  "failure": {
202
204
  "containerFailedToStart": "El contenedor no pudo iniciarse",
@@ -438,7 +440,9 @@
438
440
  "skipped": "Omitida"
439
441
  },
440
442
  "updateFailed": "No se pudo actualizar la programación",
441
- "runNowFailed": "No se pudo ejecutar ahora"
443
+ "runNowFailed": "No se pudo ejecutar ahora",
444
+ "onDemand": "Bajo demanda",
445
+ "onDemandHint": "Solo manual. Se ejecuta cuando lo activas y puede usar un modelo de suscripción de uso individual."
442
446
  },
443
447
  "fragments": {
444
448
  "serviceTitle": "Buenas prácticas del servicio",
@@ -1294,6 +1298,7 @@
1294
1298
  "visual_confirmation_ready": "Marcar como leída",
1295
1299
  "human_review": "Marcar como leída",
1296
1300
  "followup_pending": "Marcar como leída",
1301
+ "initiative": "Marcar como leída",
1297
1302
  "markRead": "Marcar como leída"
1298
1303
  },
1299
1304
  "toast": {
@@ -2549,7 +2554,8 @@
2549
2554
  "clarity_review": "Revision de claridad",
2550
2555
  "release_regression": "Regresion de version",
2551
2556
  "human_test_ready": "Listo para pruebas humanas",
2552
- "visual_confirmation_ready": "Listo para confirmacion visual"
2557
+ "visual_confirmation_ready": "Listo para confirmacion visual",
2558
+ "initiative": "Actualizaciones de la iniciativa"
2553
2559
  },
2554
2560
  "role": {
2555
2561
  "engineering": "Ingenieria",
@@ -4021,6 +4027,9 @@
4021
4027
  "inspector": {
4022
4028
  "runPlanning": "Ejecutar planificacion",
4023
4029
  "answerPlanning": "Responder preguntas de planificacion",
4030
+ "pause": "Pausar",
4031
+ "resume": "Reanudar",
4032
+ "cancel": "Cancelar iniciativa",
4024
4033
  "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
4034
  },
4026
4035
  "planning": {
@@ -196,7 +196,9 @@
196
196
  "linearTeamId": "ID d’équipe Linear",
197
197
  "footerHint": "Une seule tâche récurrente est ajoutée dans le service ; chaque exécution remplace la précédente. Son historique d’exécutions est visible dans l’inspecteur.",
198
198
  "submit": "Ajouter la pipeline récurrente",
199
- "addFailedTitle": "Impossible d’ajouter la pipeline récurrente"
199
+ "addFailedTitle": "Impossible d’ajouter la pipeline récurrente",
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."
200
202
  },
201
203
  "failure": {
202
204
  "containerFailedToStart": "Le conteneur n’a pas pu démarrer",
@@ -438,7 +440,9 @@
438
440
  "skipped": "Ignoré"
439
441
  },
440
442
  "updateFailed": "Impossible de mettre à jour la planification",
441
- "runNowFailed": "Impossible d'exécuter maintenant"
443
+ "runNowFailed": "Impossible d'exécuter maintenant",
444
+ "onDemand": "À la demande",
445
+ "onDemandHint": "Manuel uniquement. S'exécute lorsque vous le déclenchez et peut utiliser un modèle d'abonnement à usage individuel."
442
446
  },
443
447
  "fragments": {
444
448
  "serviceTitle": "Bonnes pratiques du service",
@@ -1294,6 +1298,7 @@
1294
1298
  "visual_confirmation_ready": "Marquer comme lu",
1295
1299
  "human_review": "Marquer comme lu",
1296
1300
  "followup_pending": "Marquer comme lu",
1301
+ "initiative": "Marquer comme lu",
1297
1302
  "markRead": "Marquer comme lu"
1298
1303
  },
1299
1304
  "toast": {
@@ -2549,7 +2554,8 @@
2549
2554
  "clarity_review": "Revue de clarte",
2550
2555
  "release_regression": "Regression de version",
2551
2556
  "human_test_ready": "Pret pour les tests humains",
2552
- "visual_confirmation_ready": "Pret pour la confirmation visuelle"
2557
+ "visual_confirmation_ready": "Pret pour la confirmation visuelle",
2558
+ "initiative": "Mises a jour de l'initiative"
2553
2559
  },
2554
2560
  "role": {
2555
2561
  "engineering": "Ingenierie",
@@ -4021,6 +4027,9 @@
4021
4027
  "inspector": {
4022
4028
  "runPlanning": "Lancer la planification",
4023
4029
  "answerPlanning": "Repondre aux questions de planification",
4030
+ "pause": "Mettre en pause",
4031
+ "resume": "Reprendre",
4032
+ "cancel": "Annuler l'initiative",
4024
4033
  "hint": "Le pipeline de planification explore le code, redige le plan multiphase pour approbation, puis valide le document de suivi dans le depot."
4025
4034
  },
4026
4035
  "planning": {
@@ -196,7 +196,9 @@
196
196
  "linearTeamId": "מזהה צוות Linear",
197
197
  "footerHint": "משימה מחזורית אחת נוספת בתוך השירות; כל ריצה מחליפה את הקודמת. היסטוריית הריצות שלה מוצגת במפקח.",
198
198
  "submit": "הוסף צינור מחזורי",
199
- "addFailedTitle": "לא ניתן היה להוסיף צינור מחזורי"
199
+ "addFailedTitle": "לא ניתן היה להוסיף צינור מחזורי",
200
+ "onDemand": "לפי דרישה (ידני בלבד)",
201
+ "onDemandHint": "רץ רק כשאתה מפעיל אותו, ללא תזמון. מכיוון שאתה נוכח בכל פעם, המשימה יכולה להשתמש במודל מנוי לשימוש אישי."
200
202
  },
201
203
  "failure": {
202
204
  "containerFailedToStart": "מכל הקונטיינר נכשל בהפעלה",
@@ -438,7 +440,9 @@
438
440
  "skipped": "דולג"
439
441
  },
440
442
  "updateFailed": "לא ניתן לעדכן את לוח הזמנים",
441
- "runNowFailed": "לא ניתן להריץ עכשיו"
443
+ "runNowFailed": "לא ניתן להריץ עכשיו",
444
+ "onDemand": "לפי דרישה",
445
+ "onDemandHint": "ידני בלבד. רץ כשאתה מפעיל אותו, ויכול להשתמש במודל מנוי לשימוש אישי."
442
446
  },
443
447
  "fragments": {
444
448
  "serviceTitle": "מומלצות עבודה לשירות",
@@ -1294,6 +1298,7 @@
1294
1298
  "visual_confirmation_ready": "סמן כנקרא",
1295
1299
  "human_review": "סמן כנקרא",
1296
1300
  "followup_pending": "סמן כנקרא",
1301
+ "initiative": "סמן כנקרא",
1297
1302
  "markRead": "סמן כנקרא"
1298
1303
  },
1299
1304
  "toast": {
@@ -2560,7 +2565,8 @@
2560
2565
  "clarity_review": "סקירת בהירות",
2561
2566
  "release_regression": "רגרסיית שחרור",
2562
2567
  "human_test_ready": "מוכן לבדיקה אנושית",
2563
- "visual_confirmation_ready": "מוכן לאישור חזותי"
2568
+ "visual_confirmation_ready": "מוכן לאישור חזותי",
2569
+ "initiative": "עדכוני יוזמה"
2564
2570
  },
2565
2571
  "role": {
2566
2572
  "engineering": "הנדסה",
@@ -4032,6 +4038,9 @@
4032
4038
  "inspector": {
4033
4039
  "runPlanning": "הרצת תכנון",
4034
4040
  "answerPlanning": "מענה על שאלות התכנון",
4041
+ "pause": "השהה",
4042
+ "resume": "המשך",
4043
+ "cancel": "ביטול היוזמה",
4035
4044
  "hint": "צינור התכנון חוקר את הקוד, מנסח את התוכנית הרב-שלבית לאישור, ואז שומר את מסמך המעקב במאגר."
4036
4045
  },
4037
4046
  "planning": {
@@ -196,7 +196,9 @@
196
196
  "linearTeamId": "Linear チーム ID",
197
197
  "footerHint": "サービス内に繰り返しタスクが 1 つ追加され、各実行が前回を置き換えます。実行履歴はインスペクターで確認できます。",
198
198
  "submit": "繰り返しパイプラインを追加",
199
- "addFailedTitle": "繰り返しパイプラインを追加できませんでした"
199
+ "addFailedTitle": "繰り返しパイプラインを追加できませんでした",
200
+ "onDemand": "オンデマンド(手動のみ)",
201
+ "onDemandHint": "スケジュールはなく、手動で実行したときのみ動作します。毎回ユーザーが立ち会うため、タスクは個人利用のサブスクリプションモデルを使用できます。"
200
202
  },
201
203
  "failure": {
202
204
  "containerFailedToStart": "コンテナの起動に失敗しました",
@@ -438,7 +440,9 @@
438
440
  "skipped": "スキップ"
439
441
  },
440
442
  "updateFailed": "スケジュールを更新できませんでした",
441
- "runNowFailed": "今すぐ実行できませんでした"
443
+ "runNowFailed": "今すぐ実行できませんでした",
444
+ "onDemand": "オンデマンド",
445
+ "onDemandHint": "手動のみ。実行したときに動作し、個人利用のサブスクリプションモデルを使用できます。"
442
446
  },
443
447
  "fragments": {
444
448
  "serviceTitle": "サービスのベストプラクティス",
@@ -1294,6 +1298,7 @@
1294
1298
  "visual_confirmation_ready": "既読にする",
1295
1299
  "human_review": "既読にする",
1296
1300
  "followup_pending": "既読にする",
1301
+ "initiative": "既読にする",
1297
1302
  "markRead": "既読にする"
1298
1303
  },
1299
1304
  "toast": {
@@ -2562,7 +2567,8 @@
2562
2567
  "clarity_review": "明確性レビュー",
2563
2568
  "release_regression": "リリースリグレッション",
2564
2569
  "human_test_ready": "人手テスト準備完了",
2565
- "visual_confirmation_ready": "ビジュアル確認準備完了"
2570
+ "visual_confirmation_ready": "ビジュアル確認準備完了",
2571
+ "initiative": "イニシアチブの更新"
2566
2572
  },
2567
2573
  "role": {
2568
2574
  "engineering": "エンジニアリング",
@@ -4034,6 +4040,9 @@
4034
4040
  "inspector": {
4035
4041
  "runPlanning": "計画を実行",
4036
4042
  "answerPlanning": "計画の質問に回答",
4043
+ "pause": "一時停止",
4044
+ "resume": "再開",
4045
+ "cancel": "イニシアチブをキャンセル",
4037
4046
  "hint": "計画パイプラインはコードベースを調査し、承認用の複数フェーズ計画を起草し、その後トラッカー文書をリポジトリにコミットします。"
4038
4047
  },
4039
4048
  "planning": {
@@ -196,7 +196,9 @@
196
196
  "linearTeamId": "ID zespołu Linear",
197
197
  "footerHint": "W usłudze dodawane jest jedno cykliczne zadanie; każde uruchomienie zastępuje poprzednie. Jego historia uruchomień jest widoczna w inspektorze.",
198
198
  "submit": "Dodaj cykliczny pipeline",
199
- "addFailedTitle": "Nie udało się dodać cyklicznego pipeline’u"
199
+ "addFailedTitle": "Nie udało się dodać cyklicznego pipeline’u",
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."
200
202
  },
201
203
  "failure": {
202
204
  "containerFailedToStart": "Nie udało się uruchomić kontenera",
@@ -438,7 +440,9 @@
438
440
  "skipped": "Pominięto"
439
441
  },
440
442
  "updateFailed": "Nie udało się zaktualizować harmonogramu",
441
- "runNowFailed": "Nie udało się uruchomić teraz"
443
+ "runNowFailed": "Nie udało się uruchomić teraz",
444
+ "onDemand": "Na żądanie",
445
+ "onDemandHint": "Tylko ręcznie. Uruchamia się po wyzwoleniu i może korzystać z modelu subskrypcji do użytku indywidualnego."
442
446
  },
443
447
  "fragments": {
444
448
  "serviceTitle": "Dobre praktyki usługi",
@@ -1294,6 +1298,7 @@
1294
1298
  "visual_confirmation_ready": "Oznacz jako przeczytane",
1295
1299
  "human_review": "Oznacz jako przeczytane",
1296
1300
  "followup_pending": "Oznacz jako przeczytane",
1301
+ "initiative": "Oznacz jako przeczytane",
1297
1302
  "markRead": "Oznacz jako przeczytane"
1298
1303
  },
1299
1304
  "toast": {
@@ -2549,7 +2554,8 @@
2549
2554
  "clarity_review": "Przeglad klarownosci",
2550
2555
  "release_regression": "Regresja wydania",
2551
2556
  "human_test_ready": "Gotowe do testow przez czlowieka",
2552
- "visual_confirmation_ready": "Gotowe do potwierdzenia wizualnego"
2557
+ "visual_confirmation_ready": "Gotowe do potwierdzenia wizualnego",
2558
+ "initiative": "Aktualizacje inicjatywy"
2553
2559
  },
2554
2560
  "role": {
2555
2561
  "engineering": "Inzynieria",
@@ -4021,6 +4027,9 @@
4021
4027
  "inspector": {
4022
4028
  "runPlanning": "Uruchom planowanie",
4023
4029
  "answerPlanning": "Odpowiedz na pytania planowania",
4030
+ "pause": "Wstrzymaj",
4031
+ "resume": "Wznow",
4032
+ "cancel": "Anuluj inicjatywe",
4024
4033
  "hint": "Pipeline planowania bada kod, przygotowuje wielofazowy plan do zatwierdzenia, a nastepnie zapisuje dokument trackera w repozytorium."
4025
4034
  },
4026
4035
  "planning": {
@@ -196,7 +196,9 @@
196
196
  "linearTeamId": "Linear takım kimliği",
197
197
  "footerHint": "Servisin içine tek bir yinelenen görev eklenir; her çalıştırma bir öncekinin yerini alır. Çalıştırma geçmişi inceleme panelinde görünür.",
198
198
  "submit": "Yinelenen pipeline ekle",
199
- "addFailedTitle": "Yinelenen pipeline eklenemedi"
199
+ "addFailedTitle": "Yinelenen pipeline eklenemedi",
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."
200
202
  },
201
203
  "failure": {
202
204
  "containerFailedToStart": "Konteyner başlatılamadı",
@@ -438,7 +440,9 @@
438
440
  "skipped": "Atlandı"
439
441
  },
440
442
  "updateFailed": "Zamanlama güncellenemedi",
441
- "runNowFailed": "Şimdi çalıştırılamadı"
443
+ "runNowFailed": "Şimdi çalıştırılamadı",
444
+ "onDemand": "İstek üzerine",
445
+ "onDemandHint": "Yalnızca manuel. Siz tetiklediğinizde çalışır ve bireysel kullanımlı bir abonelik modeli kullanabilir."
442
446
  },
443
447
  "fragments": {
444
448
  "serviceTitle": "Servis en iyi uygulamaları",
@@ -1294,6 +1298,7 @@
1294
1298
  "visual_confirmation_ready": "Okundu işaretle",
1295
1299
  "human_review": "Okundu işaretle",
1296
1300
  "followup_pending": "Okundu işaretle",
1301
+ "initiative": "Okundu işaretle",
1297
1302
  "markRead": "Okundu işaretle"
1298
1303
  },
1299
1304
  "toast": {
@@ -2562,7 +2567,8 @@
2562
2567
  "clarity_review": "Netlik incelemesi",
2563
2568
  "release_regression": "Sürüm gerilemesi",
2564
2569
  "human_test_ready": "İnsan testine hazır",
2565
- "visual_confirmation_ready": "Görsel onaya hazır"
2570
+ "visual_confirmation_ready": "Görsel onaya hazır",
2571
+ "initiative": "Girisim guncellemeleri"
2566
2572
  },
2567
2573
  "role": {
2568
2574
  "engineering": "Mühendislik",
@@ -4034,6 +4040,9 @@
4034
4040
  "inspector": {
4035
4041
  "runPlanning": "Planlamayi calistir",
4036
4042
  "answerPlanning": "Planlama sorularini yanitla",
4043
+ "pause": "Duraklat",
4044
+ "resume": "Devam et",
4045
+ "cancel": "Girisimi iptal et",
4037
4046
  "hint": "Planlama hatti kod tabanini inceler, onay icin cok asamali plani hazirlar ve ardindan izleyici belgesini depoya kaydeder."
4038
4047
  },
4039
4048
  "planning": {
@@ -196,7 +196,9 @@
196
196
  "linearTeamId": "ID команди Linear",
197
197
  "footerHint": "У сервісі додається одне періодичне завдання; кожен запуск замінює попередній. Його історія запусків доступна в інспекторі.",
198
198
  "submit": "Додати періодичний конвеєр",
199
- "addFailedTitle": "Не вдалося додати періодичний конвеєр"
199
+ "addFailedTitle": "Не вдалося додати періодичний конвеєр",
200
+ "onDemand": "За запитом (лише вручну)",
201
+ "onDemandHint": "Запускається лише коли ви його активуєте, без розкладу. Оскільки ви присутні щоразу, його завдання може використовувати модель підписки для індивідуального використання."
200
202
  },
201
203
  "failure": {
202
204
  "containerFailedToStart": "Не вдалося запустити контейнер",
@@ -438,7 +440,9 @@
438
440
  "skipped": "Пропущено"
439
441
  },
440
442
  "updateFailed": "Не вдалося оновити розклад",
441
- "runNowFailed": "Не вдалося запустити зараз"
443
+ "runNowFailed": "Не вдалося запустити зараз",
444
+ "onDemand": "За запитом",
445
+ "onDemandHint": "Лише вручну. Запускається коли ви активуєте, і може використовувати модель підписки для індивідуального використання."
442
446
  },
443
447
  "fragments": {
444
448
  "serviceTitle": "Найкращі практики сервісу",
@@ -1294,6 +1298,7 @@
1294
1298
  "visual_confirmation_ready": "Позначити прочитаним",
1295
1299
  "human_review": "Позначити прочитаним",
1296
1300
  "followup_pending": "Позначити прочитаним",
1301
+ "initiative": "Позначити прочитаним",
1297
1302
  "markRead": "Позначити прочитаним"
1298
1303
  },
1299
1304
  "toast": {
@@ -2549,7 +2554,8 @@
2549
2554
  "clarity_review": "Перевірка ясності",
2550
2555
  "release_regression": "Регресія випуску",
2551
2556
  "human_test_ready": "Готово до тестування людиною",
2552
- "visual_confirmation_ready": "Готово до візуального підтвердження"
2557
+ "visual_confirmation_ready": "Готово до візуального підтвердження",
2558
+ "initiative": "Оновлення ініціативи"
2553
2559
  },
2554
2560
  "role": {
2555
2561
  "engineering": "Інженерія",
@@ -4021,6 +4027,9 @@
4021
4027
  "inspector": {
4022
4028
  "runPlanning": "Запустити планування",
4023
4029
  "answerPlanning": "Відповісти на питання планування",
4030
+ "pause": "Призупинити",
4031
+ "resume": "Відновити",
4032
+ "cancel": "Скасувати ініціативу",
4024
4033
  "hint": "Пайплайн планування досліджує кодову базу, готує багатофазний план на затвердження, а потім комітить документ трекера до репозиторію."
4025
4034
  },
4026
4035
  "planning": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cat-factory/app",
3
- "version": "0.83.1",
3
+ "version": "0.85.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.90.0"
37
+ "@cat-factory/contracts": "0.92.0"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@toad-contracts/testing": "0.3.2",