@cat-factory/app 0.167.1 → 0.169.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.
Files changed (42) hide show
  1. package/README.md +45 -2
  2. package/app/components/auth/UserMenu.vue +9 -2
  3. package/app/components/board/AddTaskModal.vue +28 -9
  4. package/app/components/layout/BoardSwitcher.vue +21 -4
  5. package/app/components/layout/CommandBar.vue +3 -1
  6. package/app/components/layout/LanguageSwitcher.vue +9 -2
  7. package/app/components/layout/SideBar.vue +68 -15
  8. package/app/components/layout/UiModeSwitcher.vue +90 -0
  9. package/app/components/observability/StepMetricsBar.vue +36 -20
  10. package/app/components/panels/ObservabilityPanel.vue +60 -23
  11. package/app/components/panels/inspector/TaskRunSettings.vue +35 -8
  12. package/app/components/tasks/BugHuntModal.vue +3 -1
  13. package/app/components/tasks/ContextIssuePicker.vue +22 -5
  14. package/app/components/tasks/TaskImportModal.vue +1 -1
  15. package/app/composables/api/errors.ts +16 -0
  16. package/app/composables/api/tasks.ts +5 -2
  17. package/app/composables/useNavContributions.ts +3 -0
  18. package/app/docs/consumer-extensions.md +6 -1
  19. package/app/modular/nav-contributions.spec.ts +59 -1
  20. package/app/modular/nav-contributions.ts +62 -4
  21. package/app/modular/nav-gates.ts +7 -1
  22. package/app/modular/registry.spec.ts +1 -0
  23. package/app/stores/bugHunt.ts +2 -10
  24. package/app/stores/tasks.ts +7 -4
  25. package/app/stores/uiMode.spec.ts +151 -0
  26. package/app/stores/uiMode.ts +88 -0
  27. package/app/utils/observability.spec.ts +18 -18
  28. package/app/utils/observability.ts +19 -22
  29. package/app/utils/uiMode.spec.ts +67 -0
  30. package/app/utils/uiMode.ts +71 -0
  31. package/i18n/locales/de.json +35 -10
  32. package/i18n/locales/en.json +38 -10
  33. package/i18n/locales/es.json +35 -10
  34. package/i18n/locales/fr.json +35 -10
  35. package/i18n/locales/he.json +35 -10
  36. package/i18n/locales/it.json +35 -10
  37. package/i18n/locales/ja.json +35 -10
  38. package/i18n/locales/pl.json +35 -10
  39. package/i18n/locales/tr.json +35 -10
  40. package/i18n/locales/uk.json +35 -10
  41. package/nuxt.config.ts +5 -0
  42. package/package.json +2 -2
@@ -0,0 +1,67 @@
1
+ import { describe, expect, it } from 'vitest'
2
+ import { DEFAULT_UI_MODE, parseUiMode, resolveUiMode, showOverrideField, UI_MODES } from './uiMode'
3
+
4
+ describe('parseUiMode', () => {
5
+ it('accepts every known mode, case- and whitespace-insensitively', () => {
6
+ for (const mode of UI_MODES) {
7
+ expect(parseUiMode(mode)).toBe(mode)
8
+ expect(parseUiMode(` ${mode.toUpperCase()} `)).toBe(mode)
9
+ }
10
+ })
11
+
12
+ it('reports no opinion for an unset / unrecognised / non-string value', () => {
13
+ // '' is what `runtimeConfig.public.uiMode` carries when NUXT_PUBLIC_UI_MODE is unset, so
14
+ // it MUST read as "no env pin" rather than as an invalid mode.
15
+ for (const raw of ['', ' ', 'expert', 'Basic mode', undefined, null, 1, {}]) {
16
+ expect(parseUiMode(raw)).toBeNull()
17
+ }
18
+ })
19
+ })
20
+
21
+ describe('resolveUiMode', () => {
22
+ it('lets the env pin win over the stored choice', () => {
23
+ expect(resolveUiMode('basic', 'advanced')).toBe('basic')
24
+ expect(resolveUiMode('advanced', 'basic')).toBe('advanced')
25
+ })
26
+
27
+ it('falls back to the stored choice, then to the default', () => {
28
+ expect(resolveUiMode(null, 'advanced')).toBe('advanced')
29
+ expect(resolveUiMode(null, null)).toBe(DEFAULT_UI_MODE)
30
+ expect(DEFAULT_UI_MODE).toBe('basic')
31
+ })
32
+ })
33
+
34
+ describe('showOverrideField', () => {
35
+ it('shows every override control in advanced mode, set or not', () => {
36
+ expect(showOverrideField(true)).toBe(true)
37
+ expect(showOverrideField(true, null)).toBe(true)
38
+ expect(showOverrideField(true, 'preset_1')).toBe(true)
39
+ })
40
+
41
+ it('hides an unset override in basic mode', () => {
42
+ // The three shapes an unset override arrives in: absent, explicitly null, or the empty
43
+ // string a cleared picker writes. All mean "inherit the default", so nothing is concealed.
44
+ for (const unset of [undefined, null, '']) expect(showOverrideField(false, unset)).toBe(false)
45
+ expect(showOverrideField(false)).toBe(false)
46
+ })
47
+
48
+ it('reveals a SET override in basic mode so it stays visible and clearable', () => {
49
+ // The regression this guards: a block that already carries an override would otherwise run
50
+ // on settings a basic-mode user can neither see nor clear.
51
+ expect(showOverrideField(false, 'policy_strict')).toBe(true)
52
+ expect(showOverrideField(false, true)).toBe(true)
53
+ })
54
+
55
+ it('treats `false` as a real override, not as absence', () => {
56
+ // `technical: false` means "business task" — an explicit choice that must NOT be read as
57
+ // unset, which a plain truthiness check would get wrong.
58
+ expect(showOverrideField(false, false)).toBe(true)
59
+ })
60
+
61
+ it('reveals a multi-value group when any one of its values is set', () => {
62
+ // The tracker-writeback group edits three tri-states behind one heading.
63
+ expect(showOverrideField(false, null, null, null)).toBe(false)
64
+ expect(showOverrideField(false, null, false, null)).toBe(true)
65
+ expect(showOverrideField(false, null, null, true)).toBe(true)
66
+ })
67
+ })
@@ -0,0 +1,71 @@
1
+ /**
2
+ * The interface tier the SPA renders at: `basic` shows the everyday surface, `advanced`
3
+ * shows every destination and every run/pipeline option. Pure resolution logic, kept out
4
+ * of the store so it is testable without Pinia or a Nuxt runtime.
5
+ *
6
+ * Precedence is fixed and NOT negotiable per surface: the deployment's env value always
7
+ * wins over the browser-stored user choice, which wins over the `basic` default. That
8
+ * ordering is what lets an operator pin a fleet of kiosk-ish deployments to one tier
9
+ * without a per-browser reset, so `setMode` is a no-op while the env pin is present
10
+ * rather than writing a preference the resolver would then ignore.
11
+ */
12
+ export const UI_MODES = ['basic', 'advanced'] as const
13
+
14
+ export type UiMode = (typeof UI_MODES)[number]
15
+
16
+ /** The tier a deployment gets when neither env nor the browser says otherwise. */
17
+ export const DEFAULT_UI_MODE: UiMode = 'basic'
18
+
19
+ /**
20
+ * The side-navbar rail state each tier STARTS in, before the user touches the toggle. Basic
21
+ * opens railed (the icon rail is part of what makes it feel basic) and advanced opens
22
+ * expanded. A default, not a rule: the preference is per-tier and remembered, so an explicit
23
+ * choice in either tier survives both a reload and a round trip through the other tier.
24
+ */
25
+ export const DEFAULT_RAIL_COLLAPSED: Record<UiMode, boolean> = { basic: true, advanced: false }
26
+
27
+ /**
28
+ * Coerce an untrusted value (a `NUXT_PUBLIC_UI_MODE` string baked into the bundle, or a
29
+ * restored cookie/localStorage value) to a known mode. Anything unrecognised — including
30
+ * the empty string the runtime-config default carries when the env var is unset — resolves
31
+ * to `null`, i.e. "this layer has no opinion", so the next one down decides. Never throws:
32
+ * a typo'd env value must degrade to the default rather than fail the boot.
33
+ */
34
+ export function parseUiMode(raw: unknown): UiMode | null {
35
+ if (typeof raw !== 'string') return null
36
+ const value = raw.trim().toLowerCase()
37
+ return (UI_MODES as readonly string[]).includes(value) ? (value as UiMode) : null
38
+ }
39
+
40
+ /** Apply the precedence: env pin → browser-stored user choice → {@link DEFAULT_UI_MODE}. */
41
+ export function resolveUiMode(env: UiMode | null, stored: UiMode | null): UiMode {
42
+ return env ?? stored ?? DEFAULT_UI_MODE
43
+ }
44
+
45
+ /**
46
+ * An override value is SET when it deviates from the inherited default. `null`/`undefined`
47
+ * (and the empty string a cleared picker writes) mean "inherit"; every other value — INCLUDING
48
+ * `false`, which is a real choice on a tri-state like `technical` — is an explicit override.
49
+ */
50
+ function isOverrideSet(value: unknown): boolean {
51
+ return value != null && value !== ''
52
+ }
53
+
54
+ /**
55
+ * Whether an OVERRIDE control is rendered at the current tier.
56
+ *
57
+ * Basic mode hides the controls whose only job is to override something already decided
58
+ * elsewhere (a workspace-level default, an engine-inferred flag), which is safe ONLY while
59
+ * what remains is exactly the value the hidden control would have shown. The moment a block
60
+ * actually carries an override that stops being true: hiding it would leave a basic-mode user
61
+ * looking at a task that runs on settings they cannot see, let alone clear — and nothing else
62
+ * in the inspector surfaces them. So basic mode hides the control only while EVERY value it
63
+ * edits is unset, and reveals it (exactly as advanced mode renders it, editable, so the
64
+ * override can be cleared) as soon as one is not.
65
+ *
66
+ * Variadic because a single control can own several values — the tracker-writeback group edits
67
+ * three tri-states behind one heading, and any one of them being set must reveal the group.
68
+ */
69
+ export function showOverrideField(isAdvanced: boolean, ...values: readonly unknown[]): boolean {
70
+ return isAdvanced || values.some(isOverrideSet)
71
+ }
@@ -1997,7 +1997,8 @@
1997
1997
  "localModels": "Meine lokalen Runner",
1998
1998
  "sandbox": "Sandbox öffnen",
1999
1999
  "shortcuts": "Tastenkürzel",
2000
- "bugHunt": "Fehlerjagd"
2000
+ "bugHunt": "Fehlerjagd",
2001
+ "toggleUiMode": "Oberflächenmodus wechseln"
2001
2002
  },
2002
2003
  "keywords": {
2003
2004
  "newPipeline": "pipeline agents chain",
@@ -2018,7 +2019,8 @@
2018
2019
  "localModels": "local model runner ollama lm studio llamacpp vllm endpoint",
2019
2020
  "sandbox": "sandbox prompt model test experiment judge fixture benchmark evaluate",
2020
2021
  "shortcuts": "keyboard shortcuts keys hotkeys cheatsheet help",
2021
- "bugHunt": "fehler bug jagd triage backlog tracker nicht zugewiesen"
2022
+ "bugHunt": "fehler bug jagd triage backlog tracker nicht zugewiesen",
2023
+ "toggleUiMode": "oberfläche modus einfach erweitert anzeigen ausblenden"
2022
2024
  }
2023
2025
  },
2024
2026
  "shortcuts": {
@@ -2904,13 +2906,23 @@
2904
2906
  "transportOverhead": "Transport-Overhead",
2905
2907
  "modelExecution": "Modellausführung",
2906
2908
  "truncated": "{count} abgeschnitten | {count} abgeschnitten",
2907
- "cached": "{tokens} gecacht"
2909
+ "inputTokensHint": "Eingabe- / Ausgabe-Tokens insgesamt. Die Eingabe zählt auch gecachte Tokens mit: Sie belegen weiterhin das Kontextfenster, genau wie es die Kontextanzeige von Claude Code zählt.",
2910
+ "fresh": "{tokens} frisch",
2911
+ "freshHint": "Eingabe, die von Grund auf verarbeitet wurde, ohne Anteil aus dem Cache",
2912
+ "cacheRead": "{tokens} aus dem Cache gelesen",
2913
+ "cacheReadHint": "Eingabe-Tokens, die aus dem Cache des Providers bedient wurden (etwa 0,1x der Preis frischer Eingabe-Tokens)",
2914
+ "cacheWrite": "{tokens} in den Cache geschrieben",
2915
+ "cacheWriteHint": "Eingabe-Tokens, die in den Cache des Providers geschrieben wurden (1,25x bis 2x der Preis frischer Eingabe-Tokens)"
2908
2916
  },
2909
2917
  "metricsBar": {
2910
2918
  "calls": "{count} Aufruf | {count} Aufrufe",
2911
- "promptCompletionTokens": "Frische (nicht gecachte) Prompt-/Completion-Tokens",
2912
- "cachedTokens": "({tokens} zwischengespeichert)",
2913
- "cachedTokensHint": "Prompt-Tokens, die aus dem Cache des Providers bedient wurden",
2919
+ "inputCompletionTokens": "Eingabe- / Ausgabe-Tokens insgesamt. Die Eingabe zählt auch gecachte Tokens mit: Sie belegen weiterhin das Kontextfenster, genau wie es die Kontextanzeige von Claude Code zählt.",
2920
+ "fresh": "{tokens} frisch",
2921
+ "freshHint": "Eingabe, die von Grund auf verarbeitet wurde, ohne Anteil aus dem Cache",
2922
+ "cacheRead": "{tokens} aus dem Cache gelesen",
2923
+ "cacheReadHint": "Eingabe-Tokens, die aus dem Cache des Providers bedient wurden (etwa 0,1x der Preis frischer Eingabe-Tokens)",
2924
+ "cacheWrite": "{tokens} in den Cache geschrieben",
2925
+ "cacheWriteHint": "Eingabe-Tokens, die in den Cache des Providers geschrieben wurden (1,25x bis 2x der Preis frischer Eingabe-Tokens)",
2914
2926
  "errors": "{count} Fehler | {count} Fehler",
2915
2927
  "warnings": "{count} Warnung | {count} Warnungen",
2916
2928
  "outputLimit": "Ausgabelimit",
@@ -2920,7 +2932,7 @@
2920
2932
  "modelExecution": "Modellausführung"
2921
2933
  },
2922
2934
  "call": {
2923
- "tokensTitle": "{prompt} Prompt- / {completion} Completion-Tokens",
2935
+ "tokensTitle": "{input} Eingabe-Tokens (davon {fresh} frisch) / {completion} Ausgabe-Tokens",
2924
2936
  "outputUsedVsLimit": "Ausgabe genutzt vs. Limit",
2925
2937
  "transportVsExecution": "Transport-Overhead / Modellausführung",
2926
2938
  "error": "Fehler",
@@ -2930,7 +2942,9 @@
2930
2942
  "streamed": "gestreamt",
2931
2943
  "buffered": "gepuffert",
2932
2944
  "maxTokens": "max_tokens {value}",
2933
- "promptCached": "{cached}/{prompt} Prompt zwischengespeichert",
2945
+ "fresh": "{tokens} frisch",
2946
+ "cacheRead": "{tokens} aus dem Cache gelesen",
2947
+ "cacheWrite": "{tokens} in den Cache geschrieben",
2934
2948
  "total": "gesamt {duration}",
2935
2949
  "prompt": "Prompt",
2936
2950
  "promptPrefixOmitted": "(nur neue Nachrichten: {count} frühere ausgelassen)",
@@ -3247,10 +3261,11 @@
3247
3261
  "searchPlaceholder": "Issues durchsuchen oder eine URL/einen Schlüssel einfügen…",
3248
3262
  "refPlaceholder": "Eine Issue-URL oder einen -Schlüssel einfügen…",
3249
3263
  "searchFailed": "Suche fehlgeschlagen: {error}",
3264
+ "searchNeedsRepo": "Dieser Service ist noch mit keinem Repository verknüpft, es gibt also nichts zu durchsuchen. Verknüpfen Sie ihn mit einem Repository oder fügen Sie eine Issue-URL ein, um ein Issue direkt anzuhängen.",
3250
3265
  "imported": "importiert",
3251
3266
  "attachByReference": "{ref} per Referenz anhängen",
3252
- "noMatches": "Keine passenden Issues.",
3253
- "emptySearchable": "Nach Titel suchen oder ein importiertes Issue auswählen.",
3267
+ "noMatches": "Keine passenden Issues im Repository dieses Service. Fügen Sie eine Issue-URL ein, um eines von anderswo anzuhängen.",
3268
+ "emptySearchable": "Durchsuchen Sie das Repository dieses Service nach Titel oder wählen Sie ein importiertes Issue aus.",
3254
3269
  "emptyRefOnly": "Fügen Sie eine Issue-URL oder einen -Schlüssel ein, um es anzuhängen.",
3255
3270
  "sourceLabel": "Quelle",
3256
3271
  "noSource": "Quelle wählen",
@@ -4207,6 +4222,14 @@
4207
4222
  "dismiss": "Schließen"
4208
4223
  }
4209
4224
  },
4225
+ "uiMode": {
4226
+ "switcher": "Oberfläche",
4227
+ "basic": "Einfach",
4228
+ "advanced": "Erweitert",
4229
+ "basicHint": "Nur die alltäglichen Werkzeuge. Für alles auf „Erweitert“ umschalten.",
4230
+ "advancedHint": "Alle Bereiche und alle Ausführungsoptionen.",
4231
+ "pinned": "Von dieser Installation festgelegt"
4232
+ },
4210
4233
  "common": {
4211
4234
  "loading": "Wird geladen…",
4212
4235
  "save": "Speichern",
@@ -4279,6 +4302,8 @@
4279
4302
  "menu": "Navigationsmenü",
4280
4303
  "openMenu": "Menü öffnen",
4281
4304
  "closeMenu": "Menü schließen",
4305
+ "expandSidebar": "Seitenleiste ausklappen",
4306
+ "collapseSidebar": "Seitenleiste einklappen",
4282
4307
  "commandBar": "Suchen oder einen Befehl ausführen…",
4283
4308
  "create": "Erstellen",
4284
4309
  "buildPipeline": "Eine Pipeline erstellen",
@@ -23,6 +23,17 @@
23
23
  "dismiss": "Dismiss"
24
24
  }
25
25
  },
26
+ "uiMode": {
27
+ "switcher": "Interface",
28
+ "@switcher": {
29
+ "description": "Label above the picker that chooses how much of the app is shown (Basic or Advanced). It names the app's user interface, NOT a programming interface."
30
+ },
31
+ "basic": "Basic",
32
+ "advanced": "Advanced",
33
+ "basicHint": "Everyday tools only. Switch to Advanced to see everything.",
34
+ "advancedHint": "Every destination and every run option.",
35
+ "pinned": "Set by this deployment"
36
+ },
26
37
  "common": {
27
38
  "loading": "Loading…",
28
39
  "save": "Save",
@@ -107,6 +118,8 @@
107
118
  "menu": "Navigation menu",
108
119
  "openMenu": "Open menu",
109
120
  "closeMenu": "Close menu",
121
+ "expandSidebar": "Expand sidebar",
122
+ "collapseSidebar": "Collapse sidebar",
110
123
  "commandBar": "Search or run a command…",
111
124
  "create": "Create",
112
125
  "buildPipeline": "Build a pipeline",
@@ -1421,13 +1434,23 @@
1421
1434
  "transportOverhead": "Transport overhead",
1422
1435
  "modelExecution": "Model execution",
1423
1436
  "truncated": "{count} truncated | {count} truncated",
1424
- "cached": "{tokens} cached"
1437
+ "inputTokensHint": "Total input / completion tokens. Input counts cached tokens too: they still occupy the context window, exactly as Claude Code's own context gauge counts them.",
1438
+ "fresh": "{tokens} fresh",
1439
+ "freshHint": "Input processed from scratch, with nothing served from the cache",
1440
+ "cacheRead": "{tokens} cache read",
1441
+ "cacheReadHint": "Input tokens served from the provider's cache (about 0.1x the price of fresh input)",
1442
+ "cacheWrite": "{tokens} cache write",
1443
+ "cacheWriteHint": "Input tokens written into the provider's cache (1.25x to 2x the price of fresh input)"
1425
1444
  },
1426
1445
  "metricsBar": {
1427
1446
  "calls": "{count} call | {count} calls",
1428
- "promptCompletionTokens": "Fresh (uncached) prompt / completion tokens",
1429
- "cachedTokens": "({tokens} cached)",
1430
- "cachedTokensHint": "Prompt tokens served from the provider's cache",
1447
+ "inputCompletionTokens": "Total input / completion tokens. Input counts cached tokens too: they still occupy the context window, exactly as Claude Code's own context gauge counts them.",
1448
+ "fresh": "{tokens} fresh",
1449
+ "freshHint": "Input processed from scratch, with nothing served from the cache",
1450
+ "cacheRead": "{tokens} cache read",
1451
+ "cacheReadHint": "Input tokens served from the provider's cache (about 0.1x the price of fresh input)",
1452
+ "cacheWrite": "{tokens} cache write",
1453
+ "cacheWriteHint": "Input tokens written into the provider's cache (1.25x to 2x the price of fresh input)",
1431
1454
  "errors": "{count} error | {count} errors",
1432
1455
  "warnings": "{count} warning | {count} warnings",
1433
1456
  "outputLimit": "Output limit",
@@ -1437,7 +1460,7 @@
1437
1460
  "modelExecution": "Model execution"
1438
1461
  },
1439
1462
  "call": {
1440
- "tokensTitle": "{prompt} prompt / {completion} completion tokens",
1463
+ "tokensTitle": "{input} input tokens ({fresh} of them fresh) / {completion} completion tokens",
1441
1464
  "outputUsedVsLimit": "Output used vs limit",
1442
1465
  "transportVsExecution": "Transport overhead / model execution",
1443
1466
  "error": "error",
@@ -1447,7 +1470,9 @@
1447
1470
  "streamed": "streamed",
1448
1471
  "buffered": "buffered",
1449
1472
  "maxTokens": "max_tokens {value}",
1450
- "promptCached": "{cached}/{prompt} prompt cached",
1473
+ "fresh": "{tokens} fresh",
1474
+ "cacheRead": "{tokens} cache read",
1475
+ "cacheWrite": "{tokens} cache write",
1451
1476
  "total": "total {duration}",
1452
1477
  "prompt": "Prompt",
1453
1478
  "promptPrefixOmitted": "(new messages only: {count} earlier omitted)",
@@ -2006,7 +2031,8 @@
2006
2031
  "localModels": "My local runners",
2007
2032
  "sandbox": "Open Sandbox",
2008
2033
  "shortcuts": "Keyboard shortcuts",
2009
- "bugHunt": "Bug hunt"
2034
+ "bugHunt": "Bug hunt",
2035
+ "toggleUiMode": "Switch interface mode"
2010
2036
  },
2011
2037
  "keywords": {
2012
2038
  "newPipeline": "pipeline agents chain",
@@ -2027,7 +2053,8 @@
2027
2053
  "localModels": "local model runner ollama lm studio llamacpp vllm endpoint",
2028
2054
  "sandbox": "sandbox prompt model test experiment judge fixture benchmark evaluate",
2029
2055
  "shortcuts": "keyboard shortcuts keys hotkeys cheatsheet help",
2030
- "bugHunt": "bug hunt triage backlog issue tracker unassigned"
2056
+ "bugHunt": "bug hunt triage backlog issue tracker unassigned",
2057
+ "toggleUiMode": "interface mode basic advanced simple expert show hide"
2031
2058
  }
2032
2059
  },
2033
2060
  "shortcuts": {
@@ -3646,10 +3673,11 @@
3646
3673
  "searchPlaceholder": "Search issues or paste a URL/key…",
3647
3674
  "refPlaceholder": "Paste an issue URL or key…",
3648
3675
  "searchFailed": "Search failed: {error}",
3676
+ "searchNeedsRepo": "This service isn't linked to a repository yet, so there's nothing to search. Link it to a repo, or paste an issue URL to attach one directly.",
3649
3677
  "imported": "imported",
3650
3678
  "attachByReference": "Attach {ref} by reference",
3651
- "noMatches": "No matching issues.",
3652
- "emptySearchable": "Search by title, or pick an imported issue.",
3679
+ "noMatches": "No matching issues in this service's repository. Paste an issue URL to attach one from elsewhere.",
3680
+ "emptySearchable": "Search this service's repository by title, or pick an imported issue.",
3653
3681
  "emptyRefOnly": "Paste an issue URL or key to attach it.",
3654
3682
  "sourceLabel": "Source",
3655
3683
  "noSource": "Choose a source",
@@ -23,6 +23,14 @@
23
23
  "dismiss": "Descartar"
24
24
  }
25
25
  },
26
+ "uiMode": {
27
+ "switcher": "Interfaz",
28
+ "basic": "Básica",
29
+ "advanced": "Avanzada",
30
+ "basicHint": "Solo las herramientas del día a día. Cambia a Avanzada para verlo todo.",
31
+ "advancedHint": "Todas las secciones y todas las opciones de ejecución.",
32
+ "pinned": "Definido por este despliegue"
33
+ },
26
34
  "common": {
27
35
  "loading": "Cargando…",
28
36
  "save": "Guardar",
@@ -95,6 +103,8 @@
95
103
  "menu": "Menú de navegación",
96
104
  "openMenu": "Abrir menú",
97
105
  "closeMenu": "Cerrar menú",
106
+ "expandSidebar": "Expandir barra lateral",
107
+ "collapseSidebar": "Contraer barra lateral",
98
108
  "commandBar": "Buscar o ejecutar un comando…",
99
109
  "create": "Crear",
100
110
  "buildPipeline": "Crear una canalización",
@@ -1358,13 +1368,23 @@
1358
1368
  "transportOverhead": "Sobrecarga de transporte",
1359
1369
  "modelExecution": "Ejecución del modelo",
1360
1370
  "truncated": "{count} truncada | {count} truncadas",
1361
- "cached": "{tokens} en caché"
1371
+ "inputTokensHint": "Tokens totales de entrada / salida. La entrada tambien cuenta los tokens en caché: siguen ocupando la ventana de contexto, igual que los cuenta el medidor de contexto de Claude Code.",
1372
+ "fresh": "{tokens} frescos",
1373
+ "freshHint": "Entrada procesada desde cero, sin nada servido desde la caché",
1374
+ "cacheRead": "{tokens} leídos de caché",
1375
+ "cacheReadHint": "Tokens de entrada servidos desde la caché del proveedor (unas 0,1 veces el precio de la entrada fresca)",
1376
+ "cacheWrite": "{tokens} escritos en caché",
1377
+ "cacheWriteHint": "Tokens de entrada escritos en la caché del proveedor (de 1,25 a 2 veces el precio de la entrada fresca)"
1362
1378
  },
1363
1379
  "metricsBar": {
1364
1380
  "calls": "{count} llamada | {count} llamadas",
1365
- "promptCompletionTokens": "Tokens frescos (sin caché) de prompt / completado",
1366
- "cachedTokens": "({tokens} en caché)",
1367
- "cachedTokensHint": "Tokens de prompt servidos desde la caché del proveedor",
1381
+ "inputCompletionTokens": "Tokens totales de entrada / salida. La entrada tambien cuenta los tokens en caché: siguen ocupando la ventana de contexto, igual que los cuenta el medidor de contexto de Claude Code.",
1382
+ "fresh": "{tokens} frescos",
1383
+ "freshHint": "Entrada procesada desde cero, sin nada servido desde la caché",
1384
+ "cacheRead": "{tokens} leídos de caché",
1385
+ "cacheReadHint": "Tokens de entrada servidos desde la caché del proveedor (unas 0,1 veces el precio de la entrada fresca)",
1386
+ "cacheWrite": "{tokens} escritos en caché",
1387
+ "cacheWriteHint": "Tokens de entrada escritos en la caché del proveedor (de 1,25 a 2 veces el precio de la entrada fresca)",
1368
1388
  "errors": "{count} error | {count} errores",
1369
1389
  "warnings": "{count} advertencia | {count} advertencias",
1370
1390
  "outputLimit": "Límite de salida",
@@ -1374,7 +1394,7 @@
1374
1394
  "modelExecution": "Ejecución del modelo"
1375
1395
  },
1376
1396
  "call": {
1377
- "tokensTitle": "{prompt} tokens de prompt / {completion} de completado",
1397
+ "tokensTitle": "{input} tokens de entrada ({fresh} de ellos frescos) / {completion} tokens de salida",
1378
1398
  "outputUsedVsLimit": "Salida usada frente al límite",
1379
1399
  "transportVsExecution": "Sobrecarga de transporte / ejecución del modelo",
1380
1400
  "error": "error",
@@ -1384,7 +1404,9 @@
1384
1404
  "streamed": "en streaming",
1385
1405
  "buffered": "en búfer",
1386
1406
  "maxTokens": "max_tokens {value}",
1387
- "promptCached": "{cached}/{prompt} de prompt en caché",
1407
+ "fresh": "{tokens} frescos",
1408
+ "cacheRead": "{tokens} leídos de caché",
1409
+ "cacheWrite": "{tokens} escritos en caché",
1388
1410
  "total": "total {duration}",
1389
1411
  "prompt": "Prompt",
1390
1412
  "promptPrefixOmitted": "(solo mensajes nuevos: {count} anteriores omitidos)",
@@ -1940,7 +1962,8 @@
1940
1962
  "localModels": "Mis ejecutores locales",
1941
1963
  "sandbox": "Abrir el entorno de pruebas",
1942
1964
  "shortcuts": "Atajos de teclado",
1943
- "bugHunt": "Caza de errores"
1965
+ "bugHunt": "Caza de errores",
1966
+ "toggleUiMode": "Cambiar el modo de interfaz"
1944
1967
  },
1945
1968
  "keywords": {
1946
1969
  "newPipeline": "canalización agentes cadena pipeline",
@@ -1961,7 +1984,8 @@
1961
1984
  "localModels": "modelo local ejecutor ollama lm studio llamacpp vllm endpoint",
1962
1985
  "sandbox": "entorno de pruebas prompt modelo prueba experimento juez fixture benchmark evaluar",
1963
1986
  "shortcuts": "atajos teclado teclas ayuda",
1964
- "bugHunt": "error bug caza triaje backlog incidencias sin asignar"
1987
+ "bugHunt": "error bug caza triaje backlog incidencias sin asignar",
1988
+ "toggleUiMode": "interfaz modo básico avanzado mostrar ocultar"
1965
1989
  }
1966
1990
  },
1967
1991
  "integrationsHub": {
@@ -3541,10 +3565,11 @@
3541
3565
  "searchPlaceholder": "Busca incidencias o pega una URL/clave…",
3542
3566
  "refPlaceholder": "Pega la URL o clave de una incidencia…",
3543
3567
  "searchFailed": "La búsqueda falló: {error}",
3568
+ "searchNeedsRepo": "Este servicio aún no está vinculado a un repositorio, así que no hay nada donde buscar. Vincúlalo a un repositorio o pega la URL de una incidencia para adjuntarla directamente.",
3544
3569
  "imported": "importada",
3545
3570
  "attachByReference": "Adjuntar {ref} por referencia",
3546
- "noMatches": "No hay incidencias coincidentes.",
3547
- "emptySearchable": "Busca por título o elige una incidencia importada.",
3571
+ "noMatches": "No hay incidencias coincidentes en el repositorio de este servicio. Pega la URL de una incidencia para adjuntar una de otro sitio.",
3572
+ "emptySearchable": "Busca por título en el repositorio de este servicio o elige una incidencia importada.",
3548
3573
  "emptyRefOnly": "Pega la URL o clave de una incidencia para adjuntarla.",
3549
3574
  "sourceLabel": "Fuente",
3550
3575
  "noSource": "Elige una fuente",
@@ -23,6 +23,14 @@
23
23
  "dismiss": "Fermer"
24
24
  }
25
25
  },
26
+ "uiMode": {
27
+ "switcher": "Interface",
28
+ "basic": "Basique",
29
+ "advanced": "Avancée",
30
+ "basicHint": "Uniquement les outils du quotidien. Passez en mode avancé pour tout afficher.",
31
+ "advancedHint": "Toutes les sections et toutes les options d’exécution.",
32
+ "pinned": "Défini par ce déploiement"
33
+ },
26
34
  "common": {
27
35
  "loading": "Chargement…",
28
36
  "save": "Enregistrer",
@@ -95,6 +103,8 @@
95
103
  "menu": "Menu de navigation",
96
104
  "openMenu": "Ouvrir le menu",
97
105
  "closeMenu": "Fermer le menu",
106
+ "expandSidebar": "Développer la barre latérale",
107
+ "collapseSidebar": "Réduire la barre latérale",
98
108
  "commandBar": "Rechercher ou exécuter une commande…",
99
109
  "create": "Créer",
100
110
  "buildPipeline": "Créer un pipeline",
@@ -1358,13 +1368,23 @@
1358
1368
  "transportOverhead": "Surcoût de transport",
1359
1369
  "modelExecution": "Exécution du modèle",
1360
1370
  "truncated": "{count} tronqué | {count} tronqués",
1361
- "cached": "{tokens} en cache"
1371
+ "inputTokensHint": "Total des tokens d'entrée / de sortie. L'entree compte aussi les tokens en cache : ils occupent toujours la fenêtre de contexte, exactement comme les compte la jauge de contexte de Claude Code.",
1372
+ "fresh": "{tokens} frais",
1373
+ "freshHint": "Entrée traitée de zero, sans rien servi depuis le cache",
1374
+ "cacheRead": "{tokens} lus depuis le cache",
1375
+ "cacheReadHint": "Tokens d'entrée servis depuis le cache du fournisseur (environ 0,1 fois le prix d'une entrée fraîche)",
1376
+ "cacheWrite": "{tokens} écrits dans le cache",
1377
+ "cacheWriteHint": "Tokens d'entrée écrits dans le cache du fournisseur (1,25 à 2 fois le prix d'une entrée fraîche)"
1362
1378
  },
1363
1379
  "metricsBar": {
1364
1380
  "calls": "{count} appel | {count} appels",
1365
- "promptCompletionTokens": "Tokens frais (non mis en cache) de prompt / complétion",
1366
- "cachedTokens": "({tokens} en cache)",
1367
- "cachedTokensHint": "Tokens de prompt servis depuis le cache du fournisseur",
1381
+ "inputCompletionTokens": "Total des tokens d'entrée / de sortie. L'entree compte aussi les tokens en cache : ils occupent toujours la fenêtre de contexte, exactement comme les compte la jauge de contexte de Claude Code.",
1382
+ "fresh": "{tokens} frais",
1383
+ "freshHint": "Entrée traitée de zero, sans rien servi depuis le cache",
1384
+ "cacheRead": "{tokens} lus depuis le cache",
1385
+ "cacheReadHint": "Tokens d'entrée servis depuis le cache du fournisseur (environ 0,1 fois le prix d'une entrée fraîche)",
1386
+ "cacheWrite": "{tokens} écrits dans le cache",
1387
+ "cacheWriteHint": "Tokens d'entrée écrits dans le cache du fournisseur (1,25 à 2 fois le prix d'une entrée fraîche)",
1368
1388
  "errors": "{count} erreur | {count} erreurs",
1369
1389
  "warnings": "{count} avertissement | {count} avertissements",
1370
1390
  "outputLimit": "Limite de sortie",
@@ -1374,7 +1394,7 @@
1374
1394
  "modelExecution": "Exécution du modèle"
1375
1395
  },
1376
1396
  "call": {
1377
- "tokensTitle": "{prompt} tokens de prompt / {completion} de complétion",
1397
+ "tokensTitle": "{input} tokens d'entrée (dont {fresh} frais) / {completion} tokens de sortie",
1378
1398
  "outputUsedVsLimit": "Sortie utilisée vs limite",
1379
1399
  "transportVsExecution": "Surcoût de transport / exécution du modèle",
1380
1400
  "error": "erreur",
@@ -1384,7 +1404,9 @@
1384
1404
  "streamed": "en streaming",
1385
1405
  "buffered": "en mémoire tampon",
1386
1406
  "maxTokens": "max_tokens {value}",
1387
- "promptCached": "{cached}/{prompt} prompt en cache",
1407
+ "fresh": "{tokens} frais",
1408
+ "cacheRead": "{tokens} lus depuis le cache",
1409
+ "cacheWrite": "{tokens} écrits dans le cache",
1388
1410
  "total": "total {duration}",
1389
1411
  "prompt": "Prompt",
1390
1412
  "promptPrefixOmitted": "(nouveaux messages uniquement : {count} antérieurs omis)",
@@ -1940,7 +1962,8 @@
1940
1962
  "localModels": "Mes exécuteurs locaux",
1941
1963
  "sandbox": "Ouvrir le bac à sable",
1942
1964
  "shortcuts": "Raccourcis clavier",
1943
- "bugHunt": "Chasse aux bugs"
1965
+ "bugHunt": "Chasse aux bugs",
1966
+ "toggleUiMode": "Changer le mode d'interface"
1944
1967
  },
1945
1968
  "keywords": {
1946
1969
  "newPipeline": "pipeline agents chaîne",
@@ -1961,7 +1984,8 @@
1961
1984
  "localModels": "modèle local exécuteur ollama lm studio llamacpp vllm endpoint",
1962
1985
  "sandbox": "bac à sable prompt modèle test expérience juge fixture benchmark évaluer",
1963
1986
  "shortcuts": "raccourcis clavier touches aide",
1964
- "bugHunt": "bug chasse tri backlog tickets non assignés"
1987
+ "bugHunt": "bug chasse tri backlog tickets non assignés",
1988
+ "toggleUiMode": "interface mode simple avancé afficher masquer"
1965
1989
  }
1966
1990
  },
1967
1991
  "integrationsHub": {
@@ -3541,10 +3565,11 @@
3541
3565
  "searchPlaceholder": "Rechercher des tickets ou coller une URL/clé…",
3542
3566
  "refPlaceholder": "Coller l'URL ou la clé d'un ticket…",
3543
3567
  "searchFailed": "Échec de la recherche : {error}",
3568
+ "searchNeedsRepo": "Ce service n'est encore lié à aucun dépôt, il n'y a donc rien à rechercher. Liez-le à un dépôt ou collez l'URL d'un ticket pour en joindre un directement.",
3544
3569
  "imported": "importé",
3545
3570
  "attachByReference": "Joindre {ref} par référence",
3546
- "noMatches": "Aucun ticket correspondant.",
3547
- "emptySearchable": "Recherchez par titre ou choisissez un ticket importé.",
3571
+ "noMatches": "Aucun ticket correspondant dans le dépôt de ce service. Collez l'URL d'un ticket pour en joindre un provenant d'ailleurs.",
3572
+ "emptySearchable": "Recherchez par titre dans le dépôt de ce service ou choisissez un ticket importé.",
3548
3573
  "emptyRefOnly": "Collez l'URL ou la clé d'un ticket pour le joindre.",
3549
3574
  "sourceLabel": "Source",
3550
3575
  "noSource": "Choisir une source",