@cat-factory/app 0.220.0 → 0.221.1

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,30 @@
1
+ <script setup lang="ts">
2
+ // A stored document rendered as a link to its origin page, or as a plain element when it has none.
3
+ //
4
+ // Not every document came from a page: an `upload` is a body handed to the platform through the
5
+ // public API, so it stores an empty `url`. An anchor with an empty `href` navigates to the current
6
+ // page, which reads as a link that BROKE rather than as a document that never had one — the same
7
+ // distinction kernel's `originSuffix` / `originHeaderLine` draw for the agent-facing renderers.
8
+ // One component so the three places the SPA lists documents cannot each get it half right.
9
+ //
10
+ // `hoverClass` is the caller's hover affordance, applied ONLY when there is somewhere to go: a
11
+ // hover style on an element that does not navigate is the same lie as the empty `href`, one
12
+ // rendering later. It lives here rather than at each call site so a caller cannot pass the style
13
+ // and forget the condition.
14
+ const props = defineProps<{ url: string; hoverClass?: string }>()
15
+ const { t } = useI18n()
16
+ </script>
17
+
18
+ <template>
19
+ <component
20
+ :is="props.url ? 'a' : 'span'"
21
+ :class="props.url ? props.hoverClass : undefined"
22
+ v-bind="
23
+ props.url
24
+ ? { href: props.url, title: props.url, target: '_blank', rel: 'noopener' }
25
+ : { title: t('documents.taskDocs.uploadedHint') }
26
+ "
27
+ >
28
+ <slot />
29
+ </component>
30
+ </template>
@@ -1,6 +1,7 @@
1
1
  <script setup lang="ts">
2
2
  import { DOC_KINDS } from '~/types/domain'
3
3
  import type { DocKind, DocumentLinkRole, SourceDocument } from '~/types/domain'
4
+ import DocumentOriginLink from '~/components/documents/DocumentOriginLink.vue'
4
5
  import IntegrationBackTitle from '~/components/layout/IntegrationBackTitle.vue'
5
6
 
6
7
  // Manage the workspace's per-DocKind TEMPLATE (singular) + EXEMPLAR (multi) document links (WS1).
@@ -156,14 +157,13 @@ async function unlink(doc: SourceDocument) {
156
157
  v-if="template"
157
158
  class="mt-2 flex items-center justify-between gap-2 rounded-md bg-slate-900/70 px-3 py-2"
158
159
  >
159
- <a
160
- :href="template.url"
161
- target="_blank"
162
- rel="noopener"
163
- class="truncate text-sm font-medium text-white hover:underline"
160
+ <DocumentOriginLink
161
+ :url="template.url"
162
+ class="truncate text-sm font-medium text-white"
163
+ hover-class="hover:underline"
164
164
  >
165
165
  {{ template.title }}
166
- </a>
166
+ </DocumentOriginLink>
167
167
  <UButton
168
168
  color="neutral"
169
169
  variant="ghost"
@@ -194,14 +194,13 @@ async function unlink(doc: SourceDocument) {
194
194
  :key="`${doc.source}:${doc.externalId}`"
195
195
  class="flex items-center justify-between gap-2 rounded-md bg-slate-900/70 px-3 py-2"
196
196
  >
197
- <a
198
- :href="doc.url"
199
- target="_blank"
200
- rel="noopener"
201
- class="truncate text-sm font-medium text-white hover:underline"
197
+ <DocumentOriginLink
198
+ :url="doc.url"
199
+ class="truncate text-sm font-medium text-white"
200
+ hover-class="hover:underline"
202
201
  >
203
202
  {{ doc.title }}
204
- </a>
203
+ </DocumentOriginLink>
205
204
  <UButton
206
205
  color="neutral"
207
206
  variant="ghost"
@@ -2,6 +2,7 @@
2
2
  import type { DropdownMenuItem } from '@nuxt/ui'
3
3
  import type { Block } from '~/types/domain'
4
4
  import ContextDocumentPicker from '~/components/documents/ContextDocumentPicker.vue'
5
+ import DocumentOriginLink from '~/components/documents/DocumentOriginLink.vue'
5
6
  import InspectorSection from '~/components/panels/inspector/InspectorSection.vue'
6
7
 
7
8
  // Documents (from any source) attached to a task OR an initiative as agent
@@ -129,21 +130,19 @@ async function attach(item: PendingContext) {
129
130
  />
130
131
 
131
132
  <div v-if="linked.length" class="space-y-1">
132
- <a
133
+ <DocumentOriginLink
133
134
  v-for="doc in linked"
134
135
  :key="`${doc.source}:${doc.externalId}`"
135
- :href="doc.url"
136
- :title="doc.url"
137
- target="_blank"
138
- rel="noopener"
139
- class="flex items-center gap-1.5 rounded-md border border-slate-800 bg-slate-900/60 px-2 py-1.5 text-xs text-slate-300 hover:bg-slate-800/60"
136
+ :url="doc.url"
137
+ class="flex items-center gap-1.5 rounded-md border border-slate-800 bg-slate-900/60 px-2 py-1.5 text-xs text-slate-300"
138
+ hover-class="hover:bg-slate-800/60"
140
139
  >
141
140
  <UIcon
142
- :name="documents.descriptorFor(doc.source)?.icon ?? 'i-lucide-file-text'"
141
+ :name="documents.descriptorForOrigin(doc.source)?.icon ?? 'i-lucide-file-text'"
143
142
  class="h-3.5 w-3.5 shrink-0 text-indigo-400"
144
143
  />
145
144
  <span class="truncate">{{ doc.title }}</span>
146
- </a>
145
+ </DocumentOriginLink>
147
146
  </div>
148
147
  <p v-else class="text-[11px] text-slate-500">
149
148
  {{ emptyHint }}
@@ -13,7 +13,7 @@ import {
13
13
  spawnDocumentContract,
14
14
  unlinkDocumentForKindContract,
15
15
  } from '@cat-factory/contracts'
16
- import type { DocKind, DocumentLinkRole, DocumentSourceKind } from '~/types/domain'
16
+ import type { DocKind, DocumentLinkRole, DocumentOrigin, DocumentSourceKind } from '~/types/domain'
17
17
  import type { ApiContext } from './context'
18
18
 
19
19
  /** Document sources (Confluence, Notion, …): connect, import, search, board-spawn. */
@@ -73,7 +73,7 @@ export function documentsApi({ send, ws }: ApiContext) {
73
73
 
74
74
  linkDocument: (
75
75
  workspaceId: string,
76
- body: { source: DocumentSourceKind; externalId: string; blockId: string },
76
+ body: { source: DocumentOrigin; externalId: string; blockId: string },
77
77
  ) => send(linkDocumentContract, { pathPrefix: ws(workspaceId), body }),
78
78
 
79
79
  // ---- workspace+DocKind template / exemplar links (WS1) ----------------
@@ -83,7 +83,7 @@ export function documentsApi({ send, ws }: ApiContext) {
83
83
  linkDocumentForKind: (
84
84
  workspaceId: string,
85
85
  body: {
86
- source: DocumentSourceKind
86
+ source: DocumentOrigin
87
87
  externalId: string
88
88
  role: DocumentLinkRole
89
89
  docKind: DocKind
@@ -92,7 +92,7 @@ export function documentsApi({ send, ws }: ApiContext) {
92
92
 
93
93
  unlinkDocumentForKind: (
94
94
  workspaceId: string,
95
- body: { source: DocumentSourceKind; externalId: string },
95
+ body: { source: DocumentOrigin; externalId: string },
96
96
  ) => send(unlinkDocumentForKindContract, { pathPrefix: ws(workspaceId), body }),
97
97
  }
98
98
  }
@@ -168,13 +168,30 @@ export function useContextLinking() {
168
168
  * would make it a variable, which defeats both the typed-message-key check and the extractor's
169
169
  * static scan — and the plural choice has to be made against the same count.
170
170
  */
171
+ /**
172
+ * A failure's line in the toast: TRANSLATED copy where the backend named a reason we have a
173
+ * key for, else the server's own prose.
174
+ *
175
+ * The backend does not localize (it emits `details.reason`), so a refusal a user routinely
176
+ * hits — attaching a document another task already holds — would otherwise reach them as
177
+ * English prose in every locale. The full diagnostic dump keeps the raw message regardless,
178
+ * so nothing is lost for support.
179
+ */
180
+ function describeFailure(failure: LinkFailure): string {
181
+ const reason = failure.details?.reason
182
+ if (reason === 'document_already_linked') {
183
+ return t('errors.conflict.description.document_already_linked')
184
+ }
185
+ return failure.message
186
+ }
187
+
171
188
  function presentLinkFailures(
172
189
  failures: LinkFailure[],
173
190
  blockId?: string,
174
191
  opts: { title?: (count: number) => string } = {},
175
192
  ): void {
176
193
  if (failures.length === 0) return
177
- const description = failures.map((f) => `${f.item.title}: ${f.message}`).join('\n')
194
+ const description = failures.map((f) => `${f.item.title}: ${describeFailure(f)}`).join('\n')
178
195
  const report = buildLinkFailureReport(failures, {
179
196
  workspaceId: workspace.workspaceId,
180
197
  blockId,
@@ -256,6 +256,10 @@ const CONFLICT_INFO: Record<Exclude<ConflictReason, BespokeConflictReason>, Conf
256
256
  titleKey: 'errors.conflict.title.ticket_already_linked',
257
257
  descriptionKey: 'errors.conflict.description.ticket_already_linked',
258
258
  },
259
+ document_already_linked: {
260
+ titleKey: 'errors.conflict.title.document_already_linked',
261
+ descriptionKey: 'errors.conflict.description.document_already_linked',
262
+ },
259
263
  }
260
264
 
261
265
  /**
@@ -6,10 +6,12 @@ import type {
6
6
  DocumentConnection,
7
7
  DocumentLinkRole,
8
8
  DocumentSearchResult,
9
+ DocumentOrigin,
9
10
  DocumentSourceDescriptor,
10
11
  DocumentSourceKind,
11
12
  SourceDocument,
12
13
  } from '~/types/domain'
14
+ import { isConnectableSource } from '@cat-factory/contracts'
13
15
  import { useSourceIntegration } from '~/composables/useSourceIntegration'
14
16
  import { useUpsertList } from '~/composables/useUpsertList'
15
17
  import { useWorkspaceStore } from '~/stores/workspace'
@@ -119,8 +121,21 @@ export const useDocumentsStore = defineStore('documents', () => {
119
121
  return result
120
122
  }
121
123
 
124
+ /**
125
+ * The descriptor for a STORED document's origin, or undefined when it has none.
126
+ *
127
+ * `descriptorFor` is keyed by a connectable `DocumentSourceKind`, and a stored document's
128
+ * origin is wider than that: an `upload` was handed to the platform through the API and has no
129
+ * source behind it to describe. Narrowing through the predicate DERIVED from the source
130
+ * picklist is what keeps that a typed absence rather than an `undefined` the caller trips over,
131
+ * and what makes adding a source fail the build here until it is handled.
132
+ */
133
+ function descriptorForOrigin(origin: DocumentOrigin): DocumentSourceDescriptor | undefined {
134
+ return isConnectableSource(origin) ? descriptorFor(origin) : undefined
135
+ }
136
+
122
137
  /** Attach an imported page to a block as agent context. */
123
- async function linkToBlock(blockId: string, source: DocumentSourceKind, externalId: string) {
138
+ async function linkToBlock(blockId: string, source: DocumentOrigin, externalId: string) {
124
139
  const doc = await api.linkDocument(workspace.requireId(), { source, externalId, blockId })
125
140
  upsertDoc(doc)
126
141
  return doc
@@ -148,7 +163,7 @@ export const useDocumentsStore = defineStore('documents', () => {
148
163
  * kind, then reconcile the local list (a template replaces the prior one for its kind).
149
164
  */
150
165
  async function linkForKind(
151
- source: DocumentSourceKind,
166
+ source: DocumentOrigin,
152
167
  externalId: string,
153
168
  role: DocumentLinkRole,
154
169
  docKind: DocKind,
@@ -171,7 +186,7 @@ export const useDocumentsStore = defineStore('documents', () => {
171
186
  }
172
187
 
173
188
  /** Clear a document's role tag (built-in template resumes for the kind / exemplar drops). */
174
- async function unlinkForKind(source: DocumentSourceKind, externalId: string) {
189
+ async function unlinkForKind(source: DocumentOrigin, externalId: string) {
175
190
  await api.unlinkDocumentForKind(workspace.requireId(), { source, externalId })
176
191
  roleLinks.value = roleLinks.value.filter(
177
192
  (d) => !(d.source === source && d.externalId === externalId),
@@ -187,6 +202,7 @@ export const useDocumentsStore = defineStore('documents', () => {
187
202
  connectedSources,
188
203
  anyConnected,
189
204
  descriptorFor,
205
+ descriptorForOrigin,
190
206
  connectionFor,
191
207
  isConnected,
192
208
  docsForBlock,
@@ -10,6 +10,7 @@
10
10
 
11
11
  export type {
12
12
  DocumentSourceKind,
13
+ DocumentOrigin,
13
14
  DocumentLinkRole,
14
15
  CredentialField,
15
16
  DocumentSourceDescriptor,
@@ -3681,7 +3681,8 @@
3681
3681
  "connectSourceNamed": "{source} verbinden",
3682
3682
  "empty": "Hängen Sie eine Anforderung, ein RFC oder ein PRD an, damit Agents es beim Umsetzen dieser Aufgabe sehen.",
3683
3683
  "emptyInitiative": "Hängen Sie eine Anforderung, ein RFC oder ein PRD an, damit die Planungsagenten es beim Entwerfen dieser Initiative lesen.",
3684
- "attached": "Dokument angehängt"
3684
+ "attached": "Dokument angehängt",
3685
+ "uploadedHint": "Über die API hochgeladen, daher gibt es keine Quellseite zum Öffnen."
3685
3686
  },
3686
3687
  "templates": {
3687
3688
  "title": "Dokumentvorlagen & Beispiele",
@@ -5201,6 +5202,7 @@
5201
5202
  "input_gate_not_parked": "Nichts zu beantworten",
5202
5203
  "input_gate_parked": "Über die Eingabeprüfung der Aufgabe beantworten",
5203
5204
  "ticket_already_linked": "Dieses Ticket hat bereits eine Aufgabe",
5205
+ "document_already_linked": "Dokument bereits angehängt",
5204
5206
  "dry_run_not_mergeable": "Probelauf kann nicht zusammengeführt werden"
5205
5207
  },
5206
5208
  "description": {
@@ -5237,6 +5239,7 @@
5237
5239
  "input_gate_not_parked": "Dieser Lauf wartet nicht mehr auf seine Eingabeprüfung. Möglicherweise hat sie jemand schon beantwortet oder der Lauf ist weitergelaufen.",
5238
5240
  "input_gate_parked": "Dieser Lauf wartet auf seine Eingabeprüfung, die über die Freigabe nicht beantwortet werden kann. Nutzen Sie den Hinweis am Lauf: Aufgabe ergänzen und erneut prüfen, oder trotzdem ausführen.",
5239
5241
  "ticket_already_linked": "Ein Ticket kann nur eine Aufgabe stützen. Es erneut zu verknüpfen würde der bestehenden Aufgabe genau den Kontext entziehen, mit dem sie angelegt wurde. Öffne stattdessen diese Aufgabe oder hebe die Verknüpfung des Tickets zuerst auf.",
5242
+ "document_already_linked": "Dieses Dokument ist an eine andere Aufgabe angehängt. Lösen Sie es dort zuerst, oder hängen Sie eine separate Kopie an.",
5240
5243
  "dry_run_not_mergeable": "Dieser Pull Request stammt aus einem Probelauf und kann hier nicht zusammengeführt werden. Starte die Aufgabe erneut als echten Lauf, um einen Pull Request zu erzeugen, den dieser Arbeitsbereich zusammenführt."
5241
5244
  },
5242
5245
  "action": {
@@ -643,6 +643,7 @@
643
643
  "input_gate_not_parked": "Nothing to answer",
644
644
  "input_gate_parked": "Answer it in the task's input check",
645
645
  "ticket_already_linked": "This issue already has a task",
646
+ "document_already_linked": "Document already attached",
646
647
  "dry_run_not_mergeable": "Dry run cannot be merged"
647
648
  },
648
649
  "description": {
@@ -682,6 +683,7 @@
682
683
  "input_gate_not_parked": "This run is not waiting on its input check any more. Someone may have answered it already, or the run has moved on.",
683
684
  "input_gate_parked": "This run is parked on its input check, which the approval rail cannot answer. Use the notice on the run: fix the task and re-check, or run it anyway.",
684
685
  "ticket_already_linked": "An issue can back only one task, so linking it again would strip the existing task of the context it was created with. Open that task instead, or unlink the issue first.",
686
+ "document_already_linked": "That document is attached to another task. Detach it there first, or attach a separate copy.",
685
687
  "dry_run_not_mergeable": "This pull request came from a dry run, so it can't be merged from here. Start the task again as a live run to produce a pull request this workspace will merge."
686
688
  },
687
689
  "action": {
@@ -4185,7 +4187,8 @@
4185
4187
  "connectSourceNamed": "Connect {source}",
4186
4188
  "empty": "Attach a requirement, RFC or PRD so agents see it while implementing this task.",
4187
4189
  "emptyInitiative": "Attach a requirement, RFC or PRD so the planning agents read it while shaping this initiative.",
4188
- "attached": "Document attached"
4190
+ "attached": "Document attached",
4191
+ "uploadedHint": "Uploaded through the API, so there is no source page to open."
4189
4192
  },
4190
4193
  "templates": {
4191
4194
  "title": "Document templates & examples",
@@ -577,6 +577,7 @@
577
577
  "input_gate_not_parked": "Nada que responder",
578
578
  "input_gate_parked": "Respóndelo en la comprobación de entrada de la tarea",
579
579
  "ticket_already_linked": "Esta incidencia ya tiene una tarea",
580
+ "document_already_linked": "El documento ya está adjunto",
580
581
  "dry_run_not_mergeable": "Una ejecución de prueba no se puede fusionar"
581
582
  },
582
583
  "description": {
@@ -613,6 +614,7 @@
613
614
  "input_gate_not_parked": "Esta ejecución ya no espera su comprobación de entrada. Puede que alguien la haya respondido o que la ejecución haya avanzado.",
614
615
  "input_gate_parked": "Esta ejecución está detenida en su comprobación de entrada, que la vía de aprobación no puede resolver. Usa el aviso de la ejecución: corrige la tarea y vuelve a comprobar, o ejecútala de todos modos.",
615
616
  "ticket_already_linked": "Una incidencia solo puede respaldar una tarea, así que volver a vincularla dejaría a la tarea existente sin el contexto con el que se creó. Abre esa tarea o desvincula antes la incidencia.",
617
+ "document_already_linked": "Ese documento está adjunto a otra tarea. Sepáralo allí primero o adjunta una copia aparte.",
616
618
  "dry_run_not_mergeable": "Esta pull request proviene de una ejecución de prueba, así que no se puede fusionar desde aquí. Vuelve a iniciar la tarea como ejecución real para producir una pull request que este espacio de trabajo sí fusionará."
617
619
  },
618
620
  "action": {
@@ -4060,7 +4062,8 @@
4060
4062
  "connectSourceNamed": "Conectar {source}",
4061
4063
  "empty": "Adjunta un requisito, RFC o PRD para que los agentes lo vean mientras implementan esta tarea.",
4062
4064
  "emptyInitiative": "Adjunta un requisito, RFC o PRD para que los agentes de planificación lo lean al redactar esta iniciativa.",
4063
- "attached": "Documento adjuntado"
4065
+ "attached": "Documento adjuntado",
4066
+ "uploadedHint": "Subido a través de la API, por lo que no hay página de origen que abrir."
4064
4067
  },
4065
4068
  "templates": {
4066
4069
  "title": "Plantillas y ejemplos de documentos",
@@ -577,6 +577,7 @@
577
577
  "input_gate_not_parked": "Rien à répondre",
578
578
  "input_gate_parked": "Répondez-y dans la vérification d'entrée de la tâche",
579
579
  "ticket_already_linked": "Ce ticket a déjà une tâche",
580
+ "document_already_linked": "Document déjà joint",
580
581
  "dry_run_not_mergeable": "Une exécution à blanc ne peut pas être fusionnée"
581
582
  },
582
583
  "description": {
@@ -613,6 +614,7 @@
613
614
  "input_gate_not_parked": "Cette exécution n'attend plus sa vérification d'entrée. Quelqu'un y a peut-être déjà répondu, ou l'exécution a avancé.",
614
615
  "input_gate_parked": "Cette exécution est en attente de sa vérification d'entrée, à laquelle la validation ne peut pas répondre. Utilisez l'avis sur l'exécution : corrigez la tâche et relancez la vérification, ou exécutez-la quand même.",
615
616
  "ticket_already_linked": "Un ticket ne peut alimenter qu'une seule tâche : le relier à nouveau priverait la tâche existante du contexte avec lequel elle a été créée. Ouvrez plutôt cette tâche, ou dissociez d'abord le ticket.",
617
+ "document_already_linked": "Ce document est joint à une autre tâche. Détachez-le d'abord, ou joignez-en une copie distincte.",
616
618
  "dry_run_not_mergeable": "Cette pull request provient d'une exécution à blanc et ne peut pas être fusionnée ici. Relancez la tâche en exécution réelle pour produire une pull request que cet espace de travail fusionnera."
617
619
  },
618
620
  "action": {
@@ -4060,7 +4062,8 @@
4060
4062
  "connectSourceNamed": "Connecter {source}",
4061
4063
  "empty": "Joignez une exigence, un RFC ou un PRD pour que les agents le voient pendant l'implémentation de cette tâche.",
4062
4064
  "emptyInitiative": "Joignez une exigence, une RFC ou un PRD pour que les agents de planification le lisent en rédigeant cette initiative.",
4063
- "attached": "Document joint"
4065
+ "attached": "Document joint",
4066
+ "uploadedHint": "Envoyé via l'API : aucune page source à ouvrir."
4064
4067
  },
4065
4068
  "templates": {
4066
4069
  "title": "Modèles et exemples de documents",
@@ -577,6 +577,7 @@
577
577
  "input_gate_not_parked": "אין על מה להשיב",
578
578
  "input_gate_parked": "השיבו בבדיקת הקלט של המשימה",
579
579
  "ticket_already_linked": "לכרטיס הזה כבר יש משימה",
580
+ "document_already_linked": "המסמך כבר מצורף",
580
581
  "dry_run_not_mergeable": "לא ניתן למזג הרצת יבש"
581
582
  },
582
583
  "description": {
@@ -613,6 +614,7 @@
613
614
  "input_gate_not_parked": "ההרצה כבר לא ממתינה לבדיקת הקלט. ייתכן שמישהו כבר השיב, או שההרצה התקדמה.",
614
615
  "input_gate_parked": "הרצה זו ממתינה לבדיקת הקלט שלה, ומסלול האישור אינו יכול להשיב עליה. השתמשו בהודעה שעל ההרצה: תקנו את המשימה ובדקו שוב, או הריצו בכל זאת.",
615
616
  "ticket_already_linked": "כרטיס יכול לגבות משימה אחת בלבד, ולכן קישור נוסף שלו ישלול מהמשימה הקיימת את ההקשר שאיתו נוצרה. פתחו את המשימה הזו במקום זאת, או בטלו קודם את קישור הכרטיס.",
617
+ "document_already_linked": "המסמך מצורף למשימה אחרת. נתקו אותו שם תחילה, או צרפו עותק נפרד.",
616
618
  "dry_run_not_mergeable": "בקשת המשיכה הזו הגיעה מהרצת יבש, ולכן לא ניתן למזג אותה מכאן. הפעילו את המשימה מחדש כהרצה רגילה כדי ליצור בקשת משיכה שסביבת העבודה הזו תמזג."
617
619
  },
618
620
  "action": {
@@ -4060,7 +4062,8 @@
4060
4062
  "connectSourceNamed": "חבר את {source}",
4061
4063
  "empty": "צרף דרישה, RFC או PRD כדי שהסוכנים יראו אותם בעת מימוש משימה זו.",
4062
4064
  "emptyInitiative": "צרף דרישה, RFC או PRD כדי שסוכני התכנון יקראו אותם בעת גיבוש יוזמה זו.",
4063
- "attached": "המסמך צורף"
4065
+ "attached": "המסמך צורף",
4066
+ "uploadedHint": "הועלה דרך ה-API, ולכן אין דף מקור לפתיחה."
4064
4067
  },
4065
4068
  "templates": {
4066
4069
  "title": "תבניות ודוגמאות למסמכים",
@@ -3681,7 +3681,8 @@
3681
3681
  "connectSourceNamed": "Collega {source}",
3682
3682
  "empty": "Allega un requisito, un RFC o un PRD così gli agenti lo vedono durante l'implementazione di questa attività.",
3683
3683
  "emptyInitiative": "Allega un requisito, un RFC o un PRD così gli agenti di pianificazione lo leggono mentre redigono questa iniziativa.",
3684
- "attached": "Documento allegato"
3684
+ "attached": "Documento allegato",
3685
+ "uploadedHint": "Caricato tramite l'API, quindi non c'è una pagina di origine da aprire."
3685
3686
  },
3686
3687
  "templates": {
3687
3688
  "title": "Modelli ed esempi di documenti",
@@ -5201,6 +5202,7 @@
5201
5202
  "input_gate_not_parked": "Niente a cui rispondere",
5202
5203
  "input_gate_parked": "Rispondi nel controllo di input dell'attività",
5203
5204
  "ticket_already_linked": "Questo ticket ha già un'attività",
5205
+ "document_already_linked": "Documento già allegato",
5204
5206
  "dry_run_not_mergeable": "Una prova non può essere unita"
5205
5207
  },
5206
5208
  "description": {
@@ -5237,6 +5239,7 @@
5237
5239
  "input_gate_not_parked": "Questa esecuzione non attende più il controllo dell'input. Forse qualcuno ha già risposto, o l'esecuzione è andata avanti.",
5238
5240
  "input_gate_parked": "Questa esecuzione è in attesa del suo controllo di input, a cui l'approvazione non può rispondere. Usa l'avviso sull'esecuzione: correggi l'attività e ricontrolla, oppure eseguila comunque.",
5239
5241
  "ticket_already_linked": "Un ticket può sostenere una sola attività, quindi ricollegarlo toglierebbe all'attività esistente il contesto con cui è stata creata. Apri invece quell'attività, oppure scollega prima il ticket.",
5242
+ "document_already_linked": "Quel documento è allegato a un'altra attività. Scollegalo prima da lì oppure allega una copia separata.",
5240
5243
  "dry_run_not_mergeable": "Questa pull request proviene da una prova, quindi non può essere unita da qui. Riavvia l’attività come esecuzione reale per produrre una pull request che questo spazio di lavoro unirà."
5241
5244
  },
5242
5245
  "action": {
@@ -577,6 +577,7 @@
577
577
  "input_gate_not_parked": "応答すべきものはありません",
578
578
  "input_gate_parked": "タスクの入力チェックで回答してください",
579
579
  "ticket_already_linked": "この課題にはすでにタスクがあります",
580
+ "document_already_linked": "ドキュメントは既に添付されています",
580
581
  "dry_run_not_mergeable": "ドライランはマージできません"
581
582
  },
582
583
  "description": {
@@ -613,6 +614,7 @@
613
614
  "input_gate_not_parked": "この実行はもう入力チェックを待っていません。すでに誰かが応答したか、実行が先に進んだ可能性があります。",
614
615
  "input_gate_parked": "この実行は入力チェックで停止しており、承認からは回答できません。実行の通知から、タスクを修正して再チェックするか、そのまま実行してください。",
615
616
  "ticket_already_linked": "1 つの課題が支えられるタスクは 1 つだけです。もう一度リンクすると、既存のタスクは作成時の文脈を失います。代わりにそのタスクを開くか、先に課題のリンクを解除してください。",
617
+ "document_already_linked": "そのドキュメントは別のタスクに添付されています。先にそちらで添付を解除するか、別のコピーを添付してください。",
616
618
  "dry_run_not_mergeable": "このプルリクエストはドライランによるものなので、ここからはマージできません。このワークスペースがマージするプルリクエストを作るには、タスクを通常の実行として開始し直してください。"
617
619
  },
618
620
  "action": {
@@ -4060,7 +4062,8 @@
4060
4062
  "connectSourceNamed": "{source} を接続",
4061
4063
  "empty": "要件、RFC、PRD を添付すると、このタスクの実装中にエージェントが参照できます。",
4062
4064
  "emptyInitiative": "要件、RFC、PRD を添付すると、このイニシアチブの計画作成中に計画エージェントが参照できます。",
4063
- "attached": "ドキュメントを添付しました"
4065
+ "attached": "ドキュメントを添付しました",
4066
+ "uploadedHint": "API 経由でアップロードされたため、開けるソースページはありません。"
4064
4067
  },
4065
4068
  "templates": {
4066
4069
  "title": "ドキュメントのテンプレートと例",
@@ -577,6 +577,7 @@
577
577
  "input_gate_not_parked": "Nie ma na co odpowiadać",
578
578
  "input_gate_parked": "Odpowiedz w kontroli danych wejściowych zadania",
579
579
  "ticket_already_linked": "To zgłoszenie ma już zadanie",
580
+ "document_already_linked": "Dokument jest już załączony",
580
581
  "dry_run_not_mergeable": "Uruchomienia próbnego nie można scalić"
581
582
  },
582
583
  "description": {
@@ -613,6 +614,7 @@
613
614
  "input_gate_not_parked": "Ten przebieg nie czeka już na kontrolę danych wejściowych. Ktoś mógł już na nią odpowiedzieć albo przebieg poszedł dalej.",
614
615
  "input_gate_parked": "To uruchomienie czeka na kontrolę danych wejściowych, której nie da się rozstrzygnąć przez zatwierdzenie. Skorzystaj z powiadomienia przy uruchomieniu: popraw zadanie i sprawdź ponownie albo uruchom mimo to.",
615
616
  "ticket_already_linked": "Zgłoszenie może stać za tylko jednym zadaniem, więc ponowne powiązanie pozbawiłoby istniejące zadanie kontekstu, z którym powstało. Otwórz to zadanie albo najpierw odłącz zgłoszenie.",
617
+ "document_already_linked": "Ten dokument jest załączony do innego zadania. Najpierw odłącz go tam albo załącz osobną kopię.",
616
618
  "dry_run_not_mergeable": "Ten pull request pochodzi z uruchomienia próbnego, więc nie można go tutaj scalić. Uruchom zadanie ponownie w trybie rzeczywistym, aby powstał pull request, który ta przestrzeń robocza scali."
617
619
  },
618
620
  "action": {
@@ -4060,7 +4062,8 @@
4060
4062
  "connectSourceNamed": "Połącz {source}",
4061
4063
  "empty": "Dołącz wymaganie, dokument RFC lub PRD, aby agenci widzieli je podczas realizacji tego zadania.",
4062
4064
  "emptyInitiative": "Dołącz wymaganie, dokument RFC lub PRD, aby agenci planowania przeczytali je podczas tworzenia planu tej inicjatywy.",
4063
- "attached": "Dokument dołączony"
4065
+ "attached": "Dokument dołączony",
4066
+ "uploadedHint": "Przesłano przez API, więc nie ma strony źródłowej do otwarcia."
4064
4067
  },
4065
4068
  "templates": {
4066
4069
  "title": "Szablony i przykłady dokumentów",
@@ -577,6 +577,7 @@
577
577
  "input_gate_not_parked": "Yanıtlanacak bir şey yok",
578
578
  "input_gate_parked": "Görevin girdi kontrolünden yanıtlayın",
579
579
  "ticket_already_linked": "Bu kayda ait bir görev zaten var",
580
+ "document_already_linked": "Belge zaten ekli",
580
581
  "dry_run_not_mergeable": "Prova çalışması birleştirilemez"
581
582
  },
582
583
  "description": {
@@ -613,6 +614,7 @@
613
614
  "input_gate_not_parked": "Bu çalışma artık giriş denetimini beklemiyor. Biri onu yanıtlamış ya da çalışma ilerlemiş olabilir.",
614
615
  "input_gate_parked": "Bu çalıştırma girdi kontrolünde bekliyor ve onay akışı bunu yanıtlayamaz. Çalıştırmadaki bildirimi kullanın: görevi düzeltip yeniden kontrol edin ya da yine de çalıştırın.",
615
616
  "ticket_already_linked": "Bir kayıt yalnızca tek bir görevi besleyebilir; yeniden bağlamak mevcut görevi oluşturulduğu bağlamdan yoksun bırakır. Bunun yerine o görevi açın ya da önce kaydın bağlantısını kaldırın.",
617
+ "document_already_linked": "Bu belge başka bir göreve ekli. Önce oradan ayırın ya da ayrı bir kopya ekleyin.",
616
618
  "dry_run_not_mergeable": "Bu pull request bir prova çalışmasından geliyor, bu yüzden buradan birleştirilemez. Bu çalışma alanının birleştireceği bir pull request üretmek için görevi gerçek çalışma olarak yeniden başlatın."
617
619
  },
618
620
  "action": {
@@ -4060,7 +4062,8 @@
4060
4062
  "connectSourceNamed": "{source} bağla",
4061
4063
  "empty": "Agentların bu görevi uygularken görebilmesi için bir gereksinim, RFC veya PRD ekle.",
4062
4064
  "emptyInitiative": "Planlama ajanlarının bu girişimin planını hazırlarken okuyabilmesi için bir gereksinim, RFC veya PRD ekle.",
4063
- "attached": "Belge eklendi"
4065
+ "attached": "Belge eklendi",
4066
+ "uploadedHint": "API üzerinden yüklendiği için açılacak bir kaynak sayfa yok."
4064
4067
  },
4065
4068
  "templates": {
4066
4069
  "title": "Belge şablonları ve örnekleri",
@@ -577,6 +577,7 @@
577
577
  "input_gate_not_parked": "Немає на що відповідати",
578
578
  "input_gate_parked": "Відповідайте в перевірці вхідних даних завдання",
579
579
  "ticket_already_linked": "У цього тікета вже є завдання",
580
+ "document_already_linked": "Документ уже прикріплено",
580
581
  "dry_run_not_mergeable": "Пробний запуск не можна злити"
581
582
  },
582
583
  "description": {
@@ -613,6 +614,7 @@
613
614
  "input_gate_not_parked": "Цей запуск більше не чекає на перевірку вхідних даних. Можливо, хтось уже відповів, або запуск рушив далі.",
614
615
  "input_gate_parked": "Цей запуск очікує на перевірку вхідних даних, і схвалення її не розвʼязує. Скористайтеся повідомленням на запуску: виправте завдання й перевірте ще раз або запустіть попри це.",
615
616
  "ticket_already_linked": "Тікет може живити лише одне завдання, тож повторне звʼязування позбавить наявне завдання контексту, з яким його створено. Відкрийте це завдання або спершу відʼєднайте тікет.",
617
+ "document_already_linked": "Цей документ прикріплено до іншого завдання. Спершу відкріпіть його там або прикріпіть окрему копію.",
616
618
  "dry_run_not_mergeable": "Цей pull request походить із пробного запуску, тому його не можна злити звідси. Запустіть завдання ще раз у звичайному режимі, щоб отримати pull request, який цей робочий простір зіллє."
617
619
  },
618
620
  "action": {
@@ -4060,7 +4062,8 @@
4060
4062
  "connectSourceNamed": "Підключити {source}",
4061
4063
  "empty": "Долучіть вимогу, RFC або PRD, щоб агенти бачили їх під час реалізації цього завдання.",
4062
4064
  "emptyInitiative": "Долучіть вимогу, RFC або PRD, щоб агенти планування прочитали їх під час складання плану цієї ініціативи.",
4063
- "attached": "Документ долучено"
4065
+ "attached": "Документ долучено",
4066
+ "uploadedHint": "Завантажено через API, тож немає вихідної сторінки, яку можна відкрити."
4064
4067
  },
4065
4068
  "templates": {
4066
4069
  "title": "Шаблони та приклади документів",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cat-factory/app",
3
- "version": "0.220.0",
3
+ "version": "0.221.1",
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",
@@ -40,7 +40,7 @@
40
40
  "valibot": "^1.4.2",
41
41
  "vue": "3.5.40",
42
42
  "wretch": "^3.0.9",
43
- "@cat-factory/contracts": "0.234.0"
43
+ "@cat-factory/contracts": "0.236.0"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@toad-contracts/testing": "0.3.2",