@cat-factory/app 0.279.0 → 0.280.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.
@@ -5,10 +5,16 @@
5
5
  //
6
6
  // All wire shapes are sourced from @cat-factory/contracts (single source of truth).
7
7
  // The overview / agent-kind-meta / experiment-detail composites have no exported
8
- // contract type (the routes model them inline), so they stay frontend-only below
9
- // and follow the contract's looser `string` for `bucket`/`rubric`.
8
+ // contract type (the routes model them inline), so they stay frontend-only below.
9
+ // `bucket`, `sandboxRun` and `unsupportedReason` reuse the contract's picklist types (the builder
10
+ // branches on `sandboxRun` and MAPS `unsupportedReason` to a locale key, so a widened `string`
11
+ // there would let a typo compile and a new member ship untranslated); `rubric` stays the
12
+ // contract's looser `string`, since nothing here branches on it.
10
13
 
11
14
  export type {
15
+ SandboxAgentBucket,
16
+ SandboxRunMode,
17
+ SandboxUnsupportedReason,
12
18
  SandboxPromptOrigin,
13
19
  SandboxPromptVersion,
14
20
  SandboxFixtureKind,
@@ -30,19 +36,35 @@ export type {
30
36
  } from '@cat-factory/contracts'
31
37
 
32
38
  import type {
39
+ SandboxAgentBucket,
33
40
  SandboxExperiment,
34
41
  SandboxFixture,
35
42
  SandboxFixtureKind,
36
43
  SandboxGrade,
37
44
  SandboxPromptVersion,
38
45
  SandboxRun,
46
+ SandboxRunMode,
47
+ SandboxUnsupportedReason,
39
48
  } from '@cat-factory/contracts'
40
49
 
41
50
  /** The Sandbox catalog entry for a testable agent kind (from the overview). Frontend-only. */
42
51
  export interface SandboxAgentKindMeta {
43
52
  agentKind: string
44
53
  label: string
45
- bucket: string
54
+ /** How PRODUCTION dispatches the kind (an inline call, or a container with a checkout). */
55
+ bucket: SandboxAgentBucket
56
+ /**
57
+ * How the SANDBOX runs a cell for it. `unsupported` ⇒ the builder must not offer it: creating an
58
+ * experiment for such a kind is refused server-side, so an enabled option would only ever produce
59
+ * a 400 on a surface that suggested it.
60
+ */
61
+ sandboxRun: SandboxRunMode
62
+ /**
63
+ * Why the Sandbox cannot run this kind, as the catalog's bounded CODE; null when it can. The
64
+ * builder maps it through an exhaustive `Record` to a locale key, so a new member fails the
65
+ * typecheck instead of reaching a non-English reader in English.
66
+ */
67
+ unsupportedReason: SandboxUnsupportedReason | null
46
68
  rubric: string
47
69
  /** Fixture kinds this agent is exercised against (the UI filters the library by these). */
48
70
  fixtureKinds: SandboxFixtureKind[]
@@ -0,0 +1,24 @@
1
+ import { defineAsyncComponent, type AsyncComponentLoader, type Component } from 'vue'
2
+ import AsyncViewError from '~/components/common/AsyncViewError.vue'
3
+
4
+ /**
5
+ * Define a code-split surface (a window, a panel, a modal, the step reader) that STATES it when
6
+ * its chunk fails to load.
7
+ *
8
+ * A bare `defineAsyncComponent` renders nothing on a rejected loader, and the rejection is
9
+ * routine rather than exotic: the SPA is a hashed-chunk build, so a deployment that lands while
10
+ * a tab is open makes every not-yet-fetched chunk a 404, and the first click on a window the
11
+ * session had never opened resolves to a blank screen with no message. On the surfaces these
12
+ * windows serve, that blank is the one a person approves or rejects a run from, so it reads as
13
+ * "there is nothing to review" rather than as a failure. Same rule as the backend's: absent and
14
+ * empty must never render the same.
15
+ *
16
+ * The remedy is a reload rather than a retry, because the chunk the running document is asking
17
+ * for is gone from the origin and re-requesting the same URL cannot bring it back.
18
+ *
19
+ * Use this instead of `defineAsyncComponent` for every surface the app splits out, so a
20
+ * consumer copying the nearest example copies the loud one.
21
+ */
22
+ export function defineAsyncView(loader: AsyncComponentLoader): Component {
23
+ return defineAsyncComponent({ loader, errorComponent: AsyncViewError })
24
+ }
@@ -0,0 +1,82 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest'
2
+ import { measureBlocks } from './blockRects'
3
+
4
+ function card(id: string): HTMLElement {
5
+ const el = document.createElement('div')
6
+ el.setAttribute('data-block-id', id)
7
+ return el
8
+ }
9
+
10
+ beforeEach(() => {
11
+ document.body.innerHTML = ''
12
+ })
13
+
14
+ describe('measureBlocks', () => {
15
+ it('resolves each rendered card by its block id', () => {
16
+ const a = card('a')
17
+ const b = card('b')
18
+ document.body.append(a, b)
19
+
20
+ const blocks = measureBlocks(document)
21
+ expect(blocks.elementFor('a')).toBe(a)
22
+ expect(blocks.elementFor('b')).toBe(b)
23
+ expect(blocks.elementFor('missing')).toBeNull()
24
+ })
25
+
26
+ it('resolves the first card in document order, as a bare querySelector did', () => {
27
+ const onBoard = card('a')
28
+ const inOverlay = card('a')
29
+ document.body.append(onBoard, inOverlay)
30
+
31
+ expect(measureBlocks(document).elementFor('a')).toBe(onBoard)
32
+ })
33
+
34
+ it('measures an element once per pass however many links read it', () => {
35
+ const a = card('a')
36
+ document.body.append(a)
37
+ const measure = vi.spyOn(a, 'getBoundingClientRect')
38
+
39
+ const blocks = measureBlocks(document)
40
+ const first = blocks.rectFor(a)
41
+ expect(blocks.rectFor(a)).toBe(first)
42
+ expect(measure).toHaveBeenCalledTimes(1)
43
+ })
44
+
45
+ it('is a snapshot: a later pass measures again', () => {
46
+ const a = card('a')
47
+ document.body.append(a)
48
+ const measure = vi.spyOn(a, 'getBoundingClientRect')
49
+
50
+ measureBlocks(document).rectFor(a)
51
+ measureBlocks(document).rectFor(a)
52
+ expect(measure).toHaveBeenCalledTimes(2)
53
+ })
54
+
55
+ it('queries nothing until something is actually looked up', () => {
56
+ // The edge overlay builds a pass every awake frame of a pan and, on a board with no links
57
+ // of any kind, asks it for no card at all. Deferring is what keeps that pass free.
58
+ const root = document.createElement('div')
59
+ root.append(card('a'))
60
+ document.body.append(root)
61
+ const query = vi.spyOn(root, 'querySelectorAll')
62
+
63
+ const blocks = measureBlocks(root)
64
+ expect(query).not.toHaveBeenCalled()
65
+
66
+ blocks.elementFor('a')
67
+ blocks.elementFor('a')
68
+ expect(query).toHaveBeenCalledTimes(1)
69
+ })
70
+
71
+ it('scopes the pass to the root it was given', () => {
72
+ const outside = card('a')
73
+ const root = document.createElement('div')
74
+ const inside = card('b')
75
+ root.append(inside)
76
+ document.body.append(outside, root)
77
+
78
+ const blocks = measureBlocks(root)
79
+ expect(blocks.elementFor('b')).toBe(inside)
80
+ expect(blocks.elementFor('a')).toBeNull()
81
+ })
82
+ })
@@ -0,0 +1,61 @@
1
+ /**
2
+ * One measurement pass's view of the board's rendered block cards.
3
+ *
4
+ * The two DOM-measuring drivers on the canvas (dependency edges, task expansion) resolve cards
5
+ * by `[data-block-id]`, which is what lets an arrow follow pan / zoom / drag for free. Done a
6
+ * card at a time it is also the drivers' whole cost: the edge overlay ran two
7
+ * `document.querySelector` scans plus two `getBoundingClientRect` reads PER LINK, so a task with
8
+ * five dependencies was found and measured five times in the same frame, and the expansion sweep
9
+ * ran one scan per candidate task.
10
+ *
11
+ * A pass builds this once instead: one `querySelectorAll` over the board, then map lookups, with
12
+ * each element measured at most once. First-in-document-order wins per id, matching what
13
+ * `document.querySelector` returned before, so a card also rendered outside the canvas (the focus
14
+ * view, the inspector) resolves to the same element it always did.
15
+ *
16
+ * The query itself is DEFERRED to the first lookup, so a pass that turns out to have nothing to
17
+ * resolve costs nothing. That is the common case rather than a corner: a board with no
18
+ * dependency, epic, frontend or connection link runs the edge overlay's pass on every awake
19
+ * frame of a pan and asks it for not one card, and the sweep it replaced did no DOM work there
20
+ * at all. Deferring keeps that property in the helper, where both drivers inherit it, rather
21
+ * than as a `links.length` guard at each call site that a fifth overlay would silently miss.
22
+ *
23
+ * It is still a SNAPSHOT: geometry read inside one frame must not change halfway through a pass,
24
+ * the query runs at most once whenever it runs, and the next pass builds a fresh one.
25
+ */
26
+ export type BlockMeasurements = {
27
+ /** The rendered card for a block id, or null when nothing on the page renders it. */
28
+ elementFor: (id: string) => HTMLElement | null
29
+ /** The element's viewport rect, measured once per pass. */
30
+ rectFor: (el: Element) => DOMRect
31
+ }
32
+
33
+ export const BLOCK_ID_ATTRIBUTE = 'data-block-id'
34
+
35
+ export function measureBlocks(root: ParentNode = document): BlockMeasurements {
36
+ let elements: Map<string, HTMLElement> | null = null
37
+
38
+ function index(): Map<string, HTMLElement> {
39
+ if (elements) return elements
40
+ const found = new Map<string, HTMLElement>()
41
+ for (const el of root.querySelectorAll<HTMLElement>(`[${BLOCK_ID_ATTRIBUTE}]`)) {
42
+ const id = el.getAttribute(BLOCK_ID_ATTRIBUTE)
43
+ if (id && !found.has(id)) found.set(id, el)
44
+ }
45
+ elements = found
46
+ return found
47
+ }
48
+
49
+ const rects = new WeakMap<Element, DOMRect>()
50
+
51
+ return {
52
+ elementFor: (id) => index().get(id) ?? null,
53
+ rectFor(el) {
54
+ const cached = rects.get(el)
55
+ if (cached) return cached
56
+ const rect = el.getBoundingClientRect()
57
+ rects.set(el, rect)
58
+ return rect
59
+ },
60
+ }
61
+ }
@@ -0,0 +1,101 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { createWakeGate, type WakeGateScheduler } from './boardWakeGate'
3
+
4
+ /** A hand-driven timer: `run()` fires the one scheduled callback, whatever its delay. */
5
+ function fakeScheduler() {
6
+ let nextHandle = 1
7
+ const pending = new Map<number, { run: () => void; delayMs: number }>()
8
+ const scheduler: WakeGateScheduler = {
9
+ schedule(run, delayMs) {
10
+ const handle = nextHandle++
11
+ pending.set(handle, { run, delayMs })
12
+ return handle
13
+ },
14
+ cancel(handle) {
15
+ pending.delete(handle)
16
+ },
17
+ }
18
+ return {
19
+ scheduler,
20
+ pending: () => pending.size,
21
+ delays: () => [...pending.values()].map((p) => p.delayMs),
22
+ /** Fire every scheduled callback; anything they schedule waits for the next elapse. */
23
+ elapse() {
24
+ const due = [...pending.entries()]
25
+ pending.clear()
26
+ for (const [, { run }] of due) run()
27
+ },
28
+ }
29
+ }
30
+
31
+ function gateWith(intervalMs?: number) {
32
+ const clock = fakeScheduler()
33
+ let wakes = 0
34
+ const gate = createWakeGate({
35
+ wake: () => {
36
+ wakes++
37
+ },
38
+ scheduler: clock.scheduler,
39
+ intervalMs,
40
+ })
41
+ return { clock, gate, wakes: () => wakes }
42
+ }
43
+
44
+ describe('createWakeGate', () => {
45
+ it('wakes immediately on the first request', () => {
46
+ const { gate, wakes, clock } = gateWith()
47
+ gate.request()
48
+ expect(wakes()).toBe(1)
49
+ expect(clock.pending()).toBe(1)
50
+ })
51
+
52
+ it('admits at most one wake per interval while requests keep arriving', () => {
53
+ const { gate, wakes, clock } = gateWith()
54
+ gate.request()
55
+ gate.request()
56
+ gate.request()
57
+ expect(wakes()).toBe(1)
58
+
59
+ // The suppressed requests are owed one wake, which lands when the interval ends.
60
+ clock.elapse()
61
+ expect(wakes()).toBe(2)
62
+ // ... and the wake it just admitted opens the next interval, so a continuing stream
63
+ // stays bounded rather than firing per request.
64
+ gate.request()
65
+ expect(wakes()).toBe(2)
66
+ clock.elapse()
67
+ expect(wakes()).toBe(3)
68
+ })
69
+
70
+ it('goes idle after a quiet interval, so an isolated request is never delayed', () => {
71
+ const { gate, wakes, clock } = gateWith()
72
+ gate.request()
73
+ expect(wakes()).toBe(1)
74
+
75
+ clock.elapse()
76
+ // Nothing was owed, so the interval simply closed: no wake, nothing scheduled.
77
+ expect(wakes()).toBe(1)
78
+ expect(clock.pending()).toBe(0)
79
+
80
+ gate.request()
81
+ expect(wakes()).toBe(2)
82
+ })
83
+
84
+ it('drops an owed wake when cancelled, and admits the next request immediately', () => {
85
+ const { gate, wakes, clock } = gateWith()
86
+ gate.request()
87
+ gate.request()
88
+ gate.cancel()
89
+ clock.elapse()
90
+ expect(wakes()).toBe(1)
91
+
92
+ gate.request()
93
+ expect(wakes()).toBe(2)
94
+ })
95
+
96
+ it('schedules the interval the caller configured', () => {
97
+ const { gate, clock } = gateWith(40)
98
+ gate.request()
99
+ expect(clock.delays()).toEqual([40])
100
+ })
101
+ })
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Rate limiter for the wakes the board's activity pulse raises from RENDERS.
3
+ *
4
+ * The canvas MutationObserver is deliberately broad (see `useBoardActivity`): it watches the
5
+ * whole subtree for structure plus `style`/`class`, which is what lets it catch a geometry
6
+ * change without enumerating the causes. The cost is that every Vue-driven card re-render
7
+ * wakes the two DOM-measuring loops, and each wake carries a settle tail of several frames,
8
+ * so under a steady execution-event stream a busy board never parks them: exactly the board
9
+ * where the measurement is most expensive pays for it continuously.
10
+ *
11
+ * A render is not a gesture, though. A card whose badge changed may or may not have moved its
12
+ * neighbours, and either way nobody is watching that pixel land within one frame, so these
13
+ * wakes may be COALESCED where a pointer/wheel/camera wake may not. This gate fires the first
14
+ * one straight through (an isolated change still follows within a frame) and then admits at
15
+ * most one per interval for as long as the stream lasts.
16
+ *
17
+ * The scheduler is injected so the behaviour is testable without a timer clock.
18
+ */
19
+ export type WakeGateScheduler = {
20
+ schedule: (run: () => void, delayMs: number) => number
21
+ cancel: (handle: number) => void
22
+ }
23
+
24
+ export type WakeGate = {
25
+ /** Ask for a wake: immediate when the interval is clear, coalesced onto its end otherwise. */
26
+ request: () => void
27
+ /** Drop a coalesced wake that has not fired yet. Idempotent. */
28
+ cancel: () => void
29
+ }
30
+
31
+ /**
32
+ * How long one admitted render wake covers. The settle tail of a woken loop is ~4 frames
33
+ * (~66ms at 60Hz), so this leaves a busy board measuring for a fraction of each interval
34
+ * instead of every frame, while a change that really did move a card is on screen well inside
35
+ * the window a reader would notice.
36
+ */
37
+ export const RENDER_WAKE_INTERVAL_MS = 250
38
+
39
+ export function createWakeGate(options: {
40
+ /** Raise the pulse. */
41
+ wake: () => void
42
+ scheduler: WakeGateScheduler
43
+ intervalMs?: number
44
+ }): WakeGate {
45
+ const { wake, scheduler } = options
46
+ const intervalMs = options.intervalMs ?? RENDER_WAKE_INTERVAL_MS
47
+ /** The open interval's handle, or null when no wake has been admitted recently. */
48
+ let window: number | null = null
49
+ /** Whether a request arrived while the interval was open and still owes a wake. */
50
+ let owed = false
51
+
52
+ function closeWindow() {
53
+ window = null
54
+ // A quiet interval simply ends: the next request is admitted immediately, so an isolated
55
+ // render never waits. Only a stream that kept asking re-opens the interval, which is what
56
+ // bounds it to one wake per interval for as long as it lasts.
57
+ if (!owed) return
58
+ owed = false
59
+ wake()
60
+ window = scheduler.schedule(closeWindow, intervalMs)
61
+ }
62
+
63
+ return {
64
+ request() {
65
+ if (window !== null) {
66
+ owed = true
67
+ return
68
+ }
69
+ wake()
70
+ window = scheduler.schedule(closeWindow, intervalMs)
71
+ },
72
+ cancel() {
73
+ if (window !== null) scheduler.cancel(window)
74
+ window = null
75
+ owed = false
76
+ },
77
+ }
78
+ }
@@ -6041,6 +6041,11 @@
6041
6041
  "body": "Die Bereitstellungsintegration dieses Dienstes hat den Verbindungstest nicht bestanden: {detail}. Überprüfe ihren Endpunkt und ihre Anmeldedaten und teste die Verbindung erneut, um sie auszuführen.",
6042
6042
  "action": "Infrastruktur konfigurieren"
6043
6043
  }
6044
+ },
6045
+ "asyncView": {
6046
+ "title": "Diese Ansicht konnte nicht geladen werden",
6047
+ "body": "Ihr Code konnte nicht geladen werden. Meist wurde die Anwendung aktualisiert, während dieser Tab geöffnet war, sodass die angeforderten Dateien nicht mehr auf dem Server liegen. Laden Sie neu, um die aktuelle Version zu erhalten.",
6048
+ "reload": "Neu laden"
6044
6049
  }
6045
6050
  },
6046
6051
  "slack": {
@@ -7021,9 +7026,15 @@
7021
7026
  "clarity": "Klarheit",
7022
7027
  "architecture": "Architektur",
7023
7028
  "code-review": "Code-Review",
7029
+ "estimation": "Schätzung",
7030
+ "answer-recommendation": "empfohlene Antworten",
7024
7031
  "repo-feature": "Repo-Feature",
7025
7032
  "repo-bug": "Repo-Bug"
7026
7033
  },
7034
+ "unsupportedReason": {
7035
+ "container-run-required": "Sein Ergebnis ist ein gepushter Commit. Die Bewertung braucht daher einen echten Container-Lauf gegen ein Seed-Repository; eine Inline-Zelle kann nur Text bewerten.",
7036
+ "unknown": "Dieser Agent kann nicht in der Sandbox laufen."
7037
+ },
7027
7038
  "fixtureOrigin": {
7028
7039
  "builtin": "integriert",
7029
7040
  "custom": "benutzerdefiniert"
@@ -847,6 +847,11 @@
847
847
  },
848
848
  "action": "Configure infrastructure"
849
849
  }
850
+ },
851
+ "asyncView": {
852
+ "title": "This view could not be loaded",
853
+ "body": "Its code failed to load. That usually means the app was updated while this tab was open, so the files this page is asking for are no longer on the server. Reload to pick up the current version.",
854
+ "reload": "Reload"
850
855
  }
851
856
  },
852
857
  "personalSubscriptions": {
@@ -7098,9 +7103,15 @@
7098
7103
  "clarity": "clarity",
7099
7104
  "architecture": "architecture",
7100
7105
  "code-review": "code review",
7106
+ "estimation": "estimation",
7107
+ "answer-recommendation": "recommended answers",
7101
7108
  "repo-feature": "repo feature",
7102
7109
  "repo-bug": "repo bug"
7103
7110
  },
7111
+ "unsupportedReason": {
7112
+ "container-run-required": "Its deliverable is a pushed commit, so grading it needs a real container run against a seed repository. An inline cell can only grade text.",
7113
+ "unknown": "This agent cannot run in the Sandbox."
7114
+ },
7104
7115
  "fixtureOrigin": {
7105
7116
  "builtin": "builtin",
7106
7117
  "custom": "custom"
@@ -757,6 +757,11 @@
757
757
  "body": "La integración de despliegue de este servicio falló la prueba de conexión: {detail}. Revisa su endpoint y credenciales y vuelve a probar la conexión para ejecutarla.",
758
758
  "action": "Configurar infraestructura"
759
759
  }
760
+ },
761
+ "asyncView": {
762
+ "title": "No se pudo cargar esta vista",
763
+ "body": "No se pudo cargar su código. Normalmente significa que la aplicación se actualizó mientras esta pestaña estaba abierta, así que los archivos que pide esta página ya no están en el servidor. Vuelve a cargar para obtener la versión actual.",
764
+ "reload": "Volver a cargar"
760
765
  }
761
766
  },
762
767
  "personalSubscriptions": {
@@ -6778,9 +6783,15 @@
6778
6783
  "clarity": "claridad",
6779
6784
  "architecture": "arquitectura",
6780
6785
  "code-review": "revisión de código",
6786
+ "estimation": "estimación",
6787
+ "answer-recommendation": "respuestas recomendadas",
6781
6788
  "repo-feature": "función de repositorio",
6782
6789
  "repo-bug": "error de repositorio"
6783
6790
  },
6791
+ "unsupportedReason": {
6792
+ "container-run-required": "Su entregable es un commit publicado, así que evaluarlo requiere una ejecución real en contenedor contra un repositorio semilla; una celda en línea solo puede evaluar texto.",
6793
+ "unknown": "Este agente no puede ejecutarse en el Sandbox."
6794
+ },
6784
6795
  "fixtureOrigin": {
6785
6796
  "builtin": "integrado",
6786
6797
  "custom": "personalizado"
@@ -757,6 +757,11 @@
757
757
  "body": "L’intégration de déploiement de ce service a échoué au test de connexion : {detail}. Vérifiez son point de terminaison et ses identifiants, puis retestez la connexion pour l’exécuter.",
758
758
  "action": "Configurer l’infrastructure"
759
759
  }
760
+ },
761
+ "asyncView": {
762
+ "title": "Cette vue n'a pas pu être chargée",
763
+ "body": "Son code n'a pas pu être chargé. Cela signifie généralement que l'application a été mise à jour pendant que cet onglet était ouvert : les fichiers demandés par cette page ne sont plus sur le serveur. Rechargez pour obtenir la version actuelle.",
764
+ "reload": "Recharger"
760
765
  }
761
766
  },
762
767
  "personalSubscriptions": {
@@ -6778,9 +6783,15 @@
6778
6783
  "clarity": "clarté",
6779
6784
  "architecture": "architecture",
6780
6785
  "code-review": "revue de code",
6786
+ "estimation": "estimation",
6787
+ "answer-recommendation": "réponses recommandées",
6781
6788
  "repo-feature": "fonctionnalité de dépôt",
6782
6789
  "repo-bug": "bogue de dépôt"
6783
6790
  },
6791
+ "unsupportedReason": {
6792
+ "container-run-required": "Son livrable est un commit poussé : l’évaluer exige une exécution réelle en conteneur sur un dépôt de départ ; une cellule en ligne ne peut évaluer que du texte.",
6793
+ "unknown": "Cet agent ne peut pas s’exécuter dans le Sandbox."
6794
+ },
6784
6795
  "fixtureOrigin": {
6785
6796
  "builtin": "intégré",
6786
6797
  "custom": "personnalisé"
@@ -757,6 +757,11 @@
757
757
  "body": "אינטגרציית הפריסה של שירות זה נכשלה בבדיקת החיבור: {detail}. בדוק את נקודת הקצה והאישורים שלה, ואז בדוק שוב את החיבור כדי להריץ אותו.",
758
758
  "action": "הגדר תשתית"
759
759
  }
760
+ },
761
+ "asyncView": {
762
+ "title": "לא ניתן היה לטעון את התצוגה הזו",
763
+ "body": "טעינת הקוד שלה נכשלה. בדרך כלל המשמעות היא שהאפליקציה עודכנה בזמן שהלשונית הזו הייתה פתוחה, ולכן הקבצים שהדף מבקש כבר אינם בשרת. רעננו כדי לקבל את הגרסה הנוכחית.",
764
+ "reload": "רענון"
760
765
  }
761
766
  },
762
767
  "personalSubscriptions": {
@@ -6778,9 +6783,15 @@
6778
6783
  "clarity": "בהירות",
6779
6784
  "architecture": "ארכיטקטורה",
6780
6785
  "code-review": "סקירת קוד",
6786
+ "estimation": "אמדן",
6787
+ "answer-recommendation": "תשובות מומלצות",
6781
6788
  "repo-feature": "פיצ׳ר במאגר",
6782
6789
  "repo-bug": "באג במאגר"
6783
6790
  },
6791
+ "unsupportedReason": {
6792
+ "container-run-required": "התוצר שלו הוא קומיט שנדחף, ולכן הערכה שלו דורשת הרצה אמיתית בקונטיינר מול מאגר זרע; תא מוטבע יכול להעריך טקסט בלבד.",
6793
+ "unknown": "סוכן זה אינו יכול לרוץ ב-Sandbox."
6794
+ },
6784
6795
  "fixtureOrigin": {
6785
6796
  "builtin": "מובנה",
6786
6797
  "custom": "מותאם אישית"
@@ -6041,6 +6041,11 @@
6041
6041
  "body": "L’integrazione di deployment di questo servizio non ha superato il test di connessione: {detail}. Controlla il suo endpoint e le credenziali, poi riprova la connessione per eseguirla.",
6042
6042
  "action": "Configura infrastruttura"
6043
6043
  }
6044
+ },
6045
+ "asyncView": {
6046
+ "title": "Impossibile caricare questa vista",
6047
+ "body": "Il suo codice non è stato caricato. Di solito significa che l'applicazione è stata aggiornata mentre questa scheda era aperta, quindi i file richiesti da questa pagina non sono più sul server. Ricarica per ottenere la versione attuale.",
6048
+ "reload": "Ricarica"
6044
6049
  }
6045
6050
  },
6046
6051
  "slack": {
@@ -7021,9 +7026,15 @@
7021
7026
  "clarity": "chiarezza",
7022
7027
  "architecture": "architettura",
7023
7028
  "code-review": "revisione del codice",
7029
+ "estimation": "stima",
7030
+ "answer-recommendation": "risposte consigliate",
7024
7031
  "repo-feature": "funzionalità del repository",
7025
7032
  "repo-bug": "bug del repository"
7026
7033
  },
7034
+ "unsupportedReason": {
7035
+ "container-run-required": "Il suo risultato è un commit inviato, quindi valutarlo richiede un’esecuzione reale in container su un repository seme; una cella inline può valutare solo testo.",
7036
+ "unknown": "Questo agente non può essere eseguito nella Sandbox."
7037
+ },
7027
7038
  "fixtureOrigin": {
7028
7039
  "builtin": "integrata",
7029
7040
  "custom": "personalizzata"
@@ -757,6 +757,11 @@
757
757
  "body": "このサービスのデプロイ連携が接続テストに失敗しました: {detail}。エンドポイントと認証情報を確認し、接続を再テストしてから実行してください。",
758
758
  "action": "インフラを設定"
759
759
  }
760
+ },
761
+ "asyncView": {
762
+ "title": "このビューを読み込めませんでした",
763
+ "body": "コードの読み込みに失敗しました。多くの場合、このタブを開いたままアプリが更新され、このページが要求しているファイルがサーバー上に存在しなくなったことが原因です。再読み込みして最新版を取得してください。",
764
+ "reload": "再読み込み"
760
765
  }
761
766
  },
762
767
  "personalSubscriptions": {
@@ -6778,9 +6783,15 @@
6778
6783
  "clarity": "明確さ",
6779
6784
  "architecture": "アーキテクチャ",
6780
6785
  "code-review": "コードレビュー",
6786
+ "estimation": "見積もり",
6787
+ "answer-recommendation": "推奨回答",
6781
6788
  "repo-feature": "リポジトリ機能",
6782
6789
  "repo-bug": "リポジトリのバグ"
6783
6790
  },
6791
+ "unsupportedReason": {
6792
+ "container-run-required": "成果物はプッシュされたコミットのため、評価にはシード用リポジトリに対する実際のコンテナ実行が必要です。インラインのセルはテキストしか評価できません。",
6793
+ "unknown": "このエージェントはサンドボックスでは実行できません。"
6794
+ },
6784
6795
  "fixtureOrigin": {
6785
6796
  "builtin": "組み込み",
6786
6797
  "custom": "カスタム"
@@ -757,6 +757,11 @@
757
757
  "body": "Integracja wdrożeniowa tej usługi nie przeszła testu połączenia: {detail}. Sprawdź jej punkt końcowy i poświadczenia, a następnie ponownie przetestuj połączenie, aby go uruchomić.",
758
758
  "action": "Skonfiguruj infrastrukturę"
759
759
  }
760
+ },
761
+ "asyncView": {
762
+ "title": "Nie udało się wczytać tego widoku",
763
+ "body": "Nie udało się wczytać jego kodu. Zwykle oznacza to, że aplikacja została zaktualizowana, gdy ta karta była otwarta, więc plików żądanych przez tę stronę nie ma już na serwerze. Odśwież, aby pobrać aktualną wersję.",
764
+ "reload": "Odśwież"
760
765
  }
761
766
  },
762
767
  "personalSubscriptions": {
@@ -6778,9 +6783,15 @@
6778
6783
  "clarity": "klarowność",
6779
6784
  "architecture": "architektura",
6780
6785
  "code-review": "przegląd kodu",
6786
+ "estimation": "szacowanie",
6787
+ "answer-recommendation": "rekomendowane odpowiedzi",
6781
6788
  "repo-feature": "funkcja repozytorium",
6782
6789
  "repo-bug": "błąd repozytorium"
6783
6790
  },
6791
+ "unsupportedReason": {
6792
+ "container-run-required": "Jego wynikiem jest wypchnięty commit, więc ocena wymaga prawdziwego uruchomienia w kontenerze na repozytorium zalążkowym; komórka inline potrafi ocenić wyłącznie tekst.",
6793
+ "unknown": "Ten agent nie może działać w Sandboksie."
6794
+ },
6784
6795
  "fixtureOrigin": {
6785
6796
  "builtin": "wbudowany",
6786
6797
  "custom": "niestandardowy"
@@ -757,6 +757,11 @@
757
757
  "body": "Bu hizmetin dağıtım entegrasyonu bağlantı testinde başarısız oldu: {detail}. Uç noktasını ve kimlik bilgilerini kontrol edin, ardından çalıştırmak için bağlantıyı yeniden test edin.",
758
758
  "action": "Altyapıyı yapılandır"
759
759
  }
760
+ },
761
+ "asyncView": {
762
+ "title": "Bu görünüm yüklenemedi",
763
+ "body": "Kodu yüklenemedi. Bu genellikle bu sekme açıkken uygulamanın güncellendiği anlamına gelir; sayfanın istediği dosyalar artık sunucuda değildir. Geçerli sürümü almak için yeniden yükleyin.",
764
+ "reload": "Yeniden yükle"
760
765
  }
761
766
  },
762
767
  "personalSubscriptions": {
@@ -6778,9 +6783,15 @@
6778
6783
  "clarity": "netlik",
6779
6784
  "architecture": "mimari",
6780
6785
  "code-review": "kod incelemesi",
6786
+ "estimation": "tahmin",
6787
+ "answer-recommendation": "önerilen yanıtlar",
6781
6788
  "repo-feature": "depo özelliği",
6782
6789
  "repo-bug": "depo hatası"
6783
6790
  },
6791
+ "unsupportedReason": {
6792
+ "container-run-required": "Çıktısı gönderilmiş bir commit olduğundan değerlendirilmesi, bir tohum deposu üzerinde gerçek bir konteyner çalıştırması gerektirir; satır içi hücre yalnızca metni değerlendirebilir.",
6793
+ "unknown": "Bu ajan Sandbox’ta çalıştırılamaz."
6794
+ },
6784
6795
  "fixtureOrigin": {
6785
6796
  "builtin": "yerleşik",
6786
6797
  "custom": "özel"