@cat-factory/app 0.242.2 → 0.244.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.
@@ -15,7 +15,8 @@
15
15
  // directly; linking is the source toggle), so both are shown explicitly to undo
16
16
  // the common confusion that "I have the GitHub App, why is nothing surfaced?".
17
17
  import { computed, onMounted, ref, watch } from 'vue'
18
- import type { TaskSourceDiagnosticStatus, TaskSourceKind, TrackerKind } from '~/types/domain'
18
+ import type { TaskSourceKind, TaskSourceState, TrackerKind } from '~/types/domain'
19
+ import TaskSourceCard from '~/components/settings/TaskSourceCard.vue'
19
20
 
20
21
  const { t } = useI18n()
21
22
  const tracker = useTrackerStore()
@@ -50,15 +51,12 @@ onMounted(() => {
50
51
  // (no deep traversal) catches every change.
51
52
  watch(() => tracker.settings, hydrate)
52
53
 
53
- // Per-source live state (available = usable now; enabled = offered to the workspace).
54
- const github = computed(() => tasks.descriptorFor('github'))
55
- const jira = computed(() => tasks.descriptorFor('jira'))
56
- const linear = computed(() => tasks.descriptorFor('linear'))
57
-
58
54
  // A tracker can only file where it can authenticate: GitHub rides the installed
59
55
  // App, Jira/Linear need a connection. Selecting an unusable tracker is allowed (it
60
- // just won't file until set up), but we surface the gap inline.
61
- const githubAvailable = computed(() => github.value?.available ?? false)
56
+ // just won't file until set up), but we surface the gap inline. (The FILING picker is a
57
+ // closed list of the three trackers the `tracker` step can file into, unlike the LINKING
58
+ // list below, which is whatever the deployment registered.)
59
+ const githubAvailable = computed(() => tasks.descriptorFor('github')?.available ?? false)
62
60
  const jiraConnected = computed(() => tasks.isConnected('jira'))
63
61
  const linearConnected = computed(() => tasks.isConnected('linear'))
64
62
 
@@ -135,6 +133,18 @@ async function save() {
135
133
  // --- linking sources (per-source toggle, saved immediately) -------------------
136
134
  const togglingSource = ref<TaskSourceKind | null>(null)
137
135
 
136
+ /**
137
+ * Open whatever a source needs before it can be offered. A VCS-backed source (GitHub Issues,
138
+ * GitLab Issues) is missing its workspace VCS connection, which is set up on the VCS integration
139
+ * surface and NOT here: that one panel serves both providers, so a GitLab deployment lands on
140
+ * its PAT form and a GitHub one on the App install. Everything else is missing its own
141
+ * credentials, which is this source's connect form.
142
+ */
143
+ function openRemedy(source: TaskSourceState) {
144
+ if (source.ridesVcsProvider) ui.openGitHub()
145
+ else ui.openTaskConnect(source.source)
146
+ }
147
+
138
148
  async function toggleSource(source: TaskSourceKind, enabled: boolean) {
139
149
  togglingSource.value = source
140
150
  try {
@@ -187,20 +197,6 @@ async function checkSetup(source: TaskSourceKind) {
187
197
  })
188
198
  }
189
199
  }
190
-
191
- // Status → presentation for a setup-check verdict.
192
- const STATUS_UI: Record<
193
- TaskSourceDiagnosticStatus,
194
- { color: 'success' | 'warning' | 'error' | 'neutral'; icon: string }
195
- > = {
196
- ready: { color: 'success', icon: 'i-lucide-circle-check' },
197
- not_installed: { color: 'warning', icon: 'i-lucide-download' },
198
- not_connected: { color: 'warning', icon: 'i-lucide-plug' },
199
- auth_failed: { color: 'error', icon: 'i-lucide-key-round' },
200
- forbidden: { color: 'error', icon: 'i-lucide-shield-x' },
201
- unreachable: { color: 'error', icon: 'i-lucide-wifi-off' },
202
- error: { color: 'error', icon: 'i-lucide-triangle-alert' },
203
- }
204
200
  </script>
205
201
 
206
202
  <template>
@@ -370,190 +366,21 @@ const STATUS_UI: Record<
370
366
  </p>
371
367
  </div>
372
368
 
373
- <!-- GitHub Issues source -->
374
- <div class="rounded-lg border border-slate-800 bg-slate-800/40 px-3 py-2.5">
375
- <div class="flex items-center justify-between gap-2">
376
- <div class="flex min-w-0 items-center gap-2.5">
377
- <UIcon name="i-lucide-github" class="h-5 w-5 shrink-0 text-slate-300" />
378
- <div class="min-w-0">
379
- <div class="text-sm font-medium text-slate-200">
380
- {{ t('settings.issueTracker.vendor.github') }}
381
- </div>
382
- <div class="text-[11px] text-slate-500">
383
- {{
384
- githubAvailable
385
- ? t('settings.issueTracker.linking.github.available')
386
- : t('settings.issueTracker.linking.github.unavailable')
387
- }}
388
- </div>
389
- </div>
390
- </div>
391
- <div class="flex shrink-0 items-center gap-2">
392
- <UButton
393
- size="xs"
394
- color="neutral"
395
- variant="ghost"
396
- icon="i-lucide-stethoscope"
397
- :loading="tasks.checking === 'github'"
398
- @click="checkSetup('github')"
399
- >
400
- {{ t('settings.issueTracker.linking.checkSetup') }}
401
- </UButton>
402
- <USwitch
403
- v-if="githubAvailable"
404
- :model-value="github?.enabled ?? false"
405
- :loading="togglingSource === 'github'"
406
- @update:model-value="(v: boolean) => toggleSource('github', v)"
407
- />
408
- <UButton
409
- v-else
410
- size="xs"
411
- color="neutral"
412
- variant="soft"
413
- icon="i-lucide-github"
414
- @click="ui.openGitHub()"
415
- >
416
- {{ t('settings.issueTracker.linking.install') }}
417
- </UButton>
418
- </div>
419
- </div>
420
- <UAlert
421
- v-if="tasks.diagnostics.github"
422
- class="mt-2.5"
423
- :color="STATUS_UI[tasks.diagnostics.github.status].color"
424
- variant="subtle"
425
- :icon="STATUS_UI[tasks.diagnostics.github.status].icon"
426
- :description="
427
- tasks.diagnostics.github.message +
428
- (tasks.diagnostics.github.detail ? ` ${tasks.diagnostics.github.detail}` : '')
429
- "
430
- :ui="{ description: 'text-[11px]' }"
431
- />
432
- </div>
433
-
434
- <!-- Jira source -->
435
- <div class="rounded-lg border border-slate-800 bg-slate-800/40 px-3 py-2.5">
436
- <div class="flex items-center justify-between gap-2">
437
- <div class="flex min-w-0 items-center gap-2.5">
438
- <UIcon name="i-lucide-trello" class="h-5 w-5 shrink-0 text-slate-300" />
439
- <div class="min-w-0">
440
- <div class="text-sm font-medium text-slate-200">
441
- {{ t('settings.issueTracker.vendor.jira') }}
442
- </div>
443
- <div class="text-[11px] text-slate-500">
444
- {{
445
- jiraConnected
446
- ? t('settings.issueTracker.linking.connected')
447
- : t('settings.issueTracker.linking.jira.connectHint')
448
- }}
449
- </div>
450
- </div>
451
- </div>
452
- <div class="flex shrink-0 items-center gap-2">
453
- <UButton
454
- v-if="jiraConnected"
455
- size="xs"
456
- color="neutral"
457
- variant="ghost"
458
- icon="i-lucide-stethoscope"
459
- :loading="tasks.checking === 'jira'"
460
- @click="checkSetup('jira')"
461
- >
462
- {{ t('settings.issueTracker.linking.checkSetup') }}
463
- </UButton>
464
- <USwitch
465
- v-if="jira?.available"
466
- :model-value="jira?.enabled ?? false"
467
- :loading="togglingSource === 'jira'"
468
- @update:model-value="(v: boolean) => toggleSource('jira', v)"
469
- />
470
- <UButton
471
- v-else
472
- size="xs"
473
- color="neutral"
474
- variant="soft"
475
- icon="i-lucide-plug"
476
- @click="ui.openTaskConnect('jira')"
477
- >
478
- {{ t('settings.issueTracker.linking.connect') }}
479
- </UButton>
480
- </div>
481
- </div>
482
- <UAlert
483
- v-if="tasks.diagnostics.jira"
484
- class="mt-2.5"
485
- :color="STATUS_UI[tasks.diagnostics.jira.status].color"
486
- variant="subtle"
487
- :icon="STATUS_UI[tasks.diagnostics.jira.status].icon"
488
- :description="
489
- tasks.diagnostics.jira.message +
490
- (tasks.diagnostics.jira.detail ? ` ${tasks.diagnostics.jira.detail}` : '')
491
- "
492
- :ui="{ description: 'text-[11px]' }"
493
- />
494
- </div>
369
+ <TaskSourceCard
370
+ v-for="source in tasks.sources"
371
+ :key="source.source"
372
+ :state="source"
373
+ :diagnostic="tasks.diagnostics[source.source] ?? null"
374
+ :checking="tasks.checking === source.source"
375
+ :toggling="togglingSource === source.source"
376
+ @check="checkSetup(source.source)"
377
+ @toggle="(enabled: boolean) => toggleSource(source.source, enabled)"
378
+ @remedy="openRemedy(source)"
379
+ />
495
380
 
496
- <!-- Linear source -->
497
- <div class="rounded-lg border border-slate-800 bg-slate-800/40 px-3 py-2.5">
498
- <div class="flex items-center justify-between gap-2">
499
- <div class="flex min-w-0 items-center gap-2.5">
500
- <UIcon name="i-lucide-square-kanban" class="h-5 w-5 shrink-0 text-slate-300" />
501
- <div class="min-w-0">
502
- <div class="text-sm font-medium text-slate-200">
503
- {{ t('settings.issueTracker.vendor.linear') }}
504
- </div>
505
- <div class="text-[11px] text-slate-500">
506
- {{
507
- linearConnected
508
- ? t('settings.issueTracker.linking.connected')
509
- : t('settings.issueTracker.linking.linear.connectHint')
510
- }}
511
- </div>
512
- </div>
513
- </div>
514
- <div class="flex shrink-0 items-center gap-2">
515
- <UButton
516
- v-if="linearConnected"
517
- size="xs"
518
- color="neutral"
519
- variant="ghost"
520
- icon="i-lucide-stethoscope"
521
- :loading="tasks.checking === 'linear'"
522
- @click="checkSetup('linear')"
523
- >
524
- {{ t('settings.issueTracker.linking.checkSetup') }}
525
- </UButton>
526
- <USwitch
527
- v-if="linear?.available"
528
- :model-value="linear?.enabled ?? false"
529
- :loading="togglingSource === 'linear'"
530
- @update:model-value="(v: boolean) => toggleSource('linear', v)"
531
- />
532
- <UButton
533
- v-else
534
- size="xs"
535
- color="neutral"
536
- variant="soft"
537
- icon="i-lucide-plug"
538
- @click="ui.openTaskConnect('linear')"
539
- >
540
- {{ t('settings.issueTracker.linking.connect') }}
541
- </UButton>
542
- </div>
543
- </div>
544
- <UAlert
545
- v-if="tasks.diagnostics.linear"
546
- class="mt-2.5"
547
- :color="STATUS_UI[tasks.diagnostics.linear.status].color"
548
- variant="subtle"
549
- :icon="STATUS_UI[tasks.diagnostics.linear.status].icon"
550
- :description="
551
- tasks.diagnostics.linear.message +
552
- (tasks.diagnostics.linear.detail ? ` ${tasks.diagnostics.linear.detail}` : '')
553
- "
554
- :ui="{ description: 'text-[11px]' }"
555
- />
556
- </div>
381
+ <p v-if="tasks.sources.length === 0" class="text-[11px] text-slate-500">
382
+ {{ t('settings.issueTracker.linking.none') }}
383
+ </p>
557
384
  </section>
558
385
 
559
386
  <!-- 3. Writeback ---------------------------------------------------------->
@@ -0,0 +1,143 @@
1
+ <script setup lang="ts">
2
+ // One connected-source row of the issue-tracker settings panel: what the source is, whether the
3
+ // workspace can use it, the live setup check, and the on/off toggle.
4
+ //
5
+ // It renders from the source's own STATE (the descriptor the backend registry serves plus the
6
+ // workspace's live availability), so a source is a row here the moment its provider is
7
+ // registered. That is the whole reason this component exists: the panel used to hold one
8
+ // hard-coded card per built-in, which meant a newly shipped source had no setup check and no
9
+ // toggle until someone remembered to paste a fourth copy, and a deployment-registered source
10
+ // never got one at all.
11
+ //
12
+ // The single thing that still varies per source is the REMEDY for an unavailable one, and it
13
+ // varies along an axis the state names: `ridesVcsProvider` says the source authenticates through
14
+ // the workspace's VCS connection (so the fix lives on the VCS integration surface, and the copy
15
+ // names that provider), while a null one carries its own credentials (so the fix is this
16
+ // source's own connect form). Both are emitted as one `remedy` event; where it navigates is the
17
+ // panel's business.
18
+ import { computed } from 'vue'
19
+ import type { TaskSourceDiagnosticStatus, TaskSourceState } from '~/types/domain'
20
+ import { VCS_PROVIDER_LABELS } from '~/utils/vcs'
21
+
22
+ const props = defineProps<{
23
+ state: TaskSourceState
24
+ /** The last live setup-check verdict for this source, if one has been run. */
25
+ diagnostic?: {
26
+ status: TaskSourceDiagnosticStatus
27
+ message: string
28
+ detail?: string | null
29
+ } | null
30
+ /** A setup check is in flight for this source. */
31
+ checking?: boolean
32
+ /** The enable/disable toggle is in flight for this source. */
33
+ toggling?: boolean
34
+ }>()
35
+
36
+ const emit = defineEmits<{
37
+ check: []
38
+ toggle: [enabled: boolean]
39
+ remedy: []
40
+ }>()
41
+
42
+ const { t } = useI18n()
43
+
44
+ /** The brand name of the VCS connection this source rides, or null when it carries credentials. */
45
+ const vcsLabel = computed(() =>
46
+ props.state.ridesVcsProvider ? VCS_PROVIDER_LABELS[props.state.ridesVcsProvider] : null,
47
+ )
48
+
49
+ /**
50
+ * The one-line explanation under the source name: what makes it usable, or what is missing.
51
+ * Four cases rather than two, because "rides a connection you already have" and "connected with
52
+ * its own credentials" are different facts, and so are the two ways of fixing an unavailable one.
53
+ */
54
+ const subtitle = computed(() => {
55
+ const provider = vcsLabel.value
56
+ if (provider) {
57
+ return props.state.available
58
+ ? t('settings.issueTracker.linking.state.ridesConnected', { provider })
59
+ : t('settings.issueTracker.linking.state.ridesMissing', { provider })
60
+ }
61
+ return props.state.available
62
+ ? t('settings.issueTracker.linking.connected')
63
+ : t('settings.issueTracker.linking.state.notConnected')
64
+ })
65
+
66
+ /** The label of the button that leads to whatever is missing. */
67
+ const remedyLabel = computed(() =>
68
+ vcsLabel.value
69
+ ? t('settings.issueTracker.linking.connectProvider', { provider: vcsLabel.value })
70
+ : t('settings.issueTracker.linking.connect'),
71
+ )
72
+
73
+ // Status → presentation for a setup-check verdict. Exhaustive over the status vocabulary, so a
74
+ // new verdict fails the typecheck here rather than rendering with no icon.
75
+ const STATUS_UI: Record<
76
+ TaskSourceDiagnosticStatus,
77
+ { color: 'success' | 'warning' | 'error' | 'neutral'; icon: string }
78
+ > = {
79
+ ready: { color: 'success', icon: 'i-lucide-circle-check' },
80
+ not_installed: { color: 'warning', icon: 'i-lucide-download' },
81
+ not_connected: { color: 'warning', icon: 'i-lucide-plug' },
82
+ auth_failed: { color: 'error', icon: 'i-lucide-key-round' },
83
+ forbidden: { color: 'error', icon: 'i-lucide-shield-x' },
84
+ unreachable: { color: 'error', icon: 'i-lucide-wifi-off' },
85
+ error: { color: 'error', icon: 'i-lucide-triangle-alert' },
86
+ }
87
+ </script>
88
+
89
+ <template>
90
+ <div class="rounded-lg border border-slate-800 bg-slate-800/40 px-3 py-2.5">
91
+ <div class="flex items-center justify-between gap-2">
92
+ <div class="flex min-w-0 items-center gap-2.5">
93
+ <UIcon :name="state.icon" class="h-5 w-5 shrink-0 text-slate-300" />
94
+ <div class="min-w-0">
95
+ <div class="text-sm font-medium text-slate-200">{{ state.label }}</div>
96
+ <div class="text-[11px] text-slate-500">{{ subtitle }}</div>
97
+ </div>
98
+ </div>
99
+ <div class="flex shrink-0 items-center gap-2">
100
+ <!-- Offered whatever the state: the check is precisely the "why is this not working"
101
+ affordance, and its verdict distinguishes a missing connection from a broken one. -->
102
+ <UButton
103
+ size="xs"
104
+ color="neutral"
105
+ variant="ghost"
106
+ icon="i-lucide-stethoscope"
107
+ :loading="checking"
108
+ :data-testid="`task-source-check-${state.source}`"
109
+ @click="emit('check')"
110
+ >
111
+ {{ t('settings.issueTracker.linking.checkSetup') }}
112
+ </UButton>
113
+ <USwitch
114
+ v-if="state.available"
115
+ :model-value="state.enabled"
116
+ :loading="toggling"
117
+ :data-testid="`task-source-toggle-${state.source}`"
118
+ @update:model-value="(v: boolean) => emit('toggle', v)"
119
+ />
120
+ <UButton
121
+ v-else
122
+ size="xs"
123
+ color="neutral"
124
+ variant="soft"
125
+ :icon="state.icon"
126
+ :data-testid="`task-source-remedy-${state.source}`"
127
+ @click="emit('remedy')"
128
+ >
129
+ {{ remedyLabel }}
130
+ </UButton>
131
+ </div>
132
+ </div>
133
+ <UAlert
134
+ v-if="diagnostic"
135
+ class="mt-2.5"
136
+ :color="STATUS_UI[diagnostic.status].color"
137
+ variant="subtle"
138
+ :icon="STATUS_UI[diagnostic.status].icon"
139
+ :description="diagnostic.message + (diagnostic.detail ? ` ${diagnostic.detail}` : '')"
140
+ :ui="{ description: 'text-[11px]' }"
141
+ />
142
+ </div>
143
+ </template>
@@ -32,6 +32,9 @@ const jiraDescriptor: TaskSourceState = {
32
32
  refPlaceholder: 'PROJ-123',
33
33
  available: true,
34
34
  enabled: true,
35
+ supportsIntake: true,
36
+ // Jira carries its own credentials, so it rides no VCS connection.
37
+ ridesVcsProvider: null,
35
38
  }
36
39
 
37
40
  const jiraConnection: TaskConnection = { source: 'jira', label: 'acme', connectedAt: 0 }
@@ -6,11 +6,13 @@
6
6
  // member added on one side only renders as a blank chip rather than failing to compile.
7
7
 
8
8
  export type {
9
+ ObservedToolServer,
9
10
  StepToolServers,
10
11
  ToolServerUnavailableReason,
11
12
  ToolServerAllowedToolsCheck,
12
13
  ToolServerCredential,
13
14
  ToolServerNotProbeableReason,
15
+ ToolServerObservedStatus,
14
16
  ToolServerOAuthGrant,
15
17
  ToolServerOAuthStatus,
16
18
  ToolServerProbeResult,
@@ -377,27 +377,21 @@
377
377
  "linearTeamSearchPlaceholder": "Teams suchen…"
378
378
  },
379
379
  "vendor": {
380
- "github": "GitHub Issues",
381
- "jira": "Jira",
382
- "linear": "Linear"
380
+ "github": "GitHub Issues"
383
381
  },
384
382
  "linking": {
385
383
  "heading": "Issues als Kontext verknüpfen",
386
384
  "description": "Wenn eine Quelle angeboten wird, kannst du ihre Issues importieren und an eine Aufgabe anhängen, sodass Agenten die Issue-Beschreibung und Kommentare während der Umsetzung sehen. Dies ist unabhängig vom Ablage-Tracker oben.",
387
- "github": {
388
- "available": "Nutzt deine installierte GitHub-App — keine Zugangsdaten nötig.",
389
- "unavailable": "Installiere die GitHub-App (Integrationen → GitHub), um diese Quelle anzubieten."
390
- },
391
385
  "checkSetup": "Einrichtung prüfen",
392
- "install": "Installieren",
393
386
  "connected": "Verbunden.",
394
- "jira": {
395
- "connectHint": "Mit einem Jira-Konto und API-Token verbinden."
396
- },
397
- "linear": {
398
- "connectHint": "Mit einem persönlichen Linear-API-Schlüssel verbinden."
387
+ "connect": "Verbinden",
388
+ "state": {
389
+ "ridesConnected": "Nutzt die {provider}-Verbindung dieses Workspace und braucht daher keine eigenen Zugangsdaten.",
390
+ "ridesMissing": "Verbinde {provider} unter Integrationen, um diese Quelle anzubieten.",
391
+ "notConnected": "Noch nicht verbunden."
399
392
  },
400
- "connect": "Verbinden"
393
+ "connectProvider": "{provider} verbinden",
394
+ "none": "In diesem Deployment sind keine Aufgabenquellen konfiguriert."
401
395
  },
402
396
  "writeback": {
403
397
  "heading": "Rückschreiben",
@@ -2007,6 +2001,16 @@
2007
2001
  "oauthNotConnected": "Verbinden Sie dieses Board im Infrastruktur-Fenster damit. Ein Deployment ohne ENCRYPTION_KEY hat keinen Ort für eine Berechtigung, das muss ein Betreiber also zuerst setzen.",
2008
2002
  "oauthTokenFailed": "Verbinden Sie es im Infrastruktur-Fenster neu, oder warten Sie die Störung des Anbieters ab.",
2009
2003
  "overBudget": "Kürzen Sie, was der Agent deklariert, damit ein Lauf alles mitführen kann."
2004
+ },
2005
+ "observed": {
2006
+ "ready": "gestartet",
2007
+ "readyTools": "{count} Tools",
2008
+ "readyNoTools": "gestartet, keine Tools",
2009
+ "failed": "Start fehlgeschlagen",
2010
+ "needsAuth": "Autorisierung erforderlich",
2011
+ "unknown": "Zustand ungeklärt",
2012
+ "notLoaded": "nie geladen",
2013
+ "unattributed": "Die Agenten-CLI meldete einen Server, den dieser Schritt nicht eingebunden hat: {id}."
2010
2014
  }
2011
2015
  },
2012
2016
  "adherence": {
@@ -2914,6 +2918,7 @@
2914
2918
  "intake": "Issue-Aufnahme",
2915
2919
  "intakeHint": "Jeder Lauf wählt ein passendes offenes Issue aus dem Tracker und bearbeitet es von Anfang bis Ende.",
2916
2920
  "intakeNoSources": "Verbinden Sie zuerst eine Task-Quelle, um Issues daraus zu ziehen.",
2921
+ "intakeNoIntakeSources": "Eine Task-Quelle ist verbunden, aber keine der verbundenen Quellen kann bereits eine geplante Issue-Suche ausführen.",
2917
2922
  "intakeGithubRepo": "Repository",
2918
2923
  "intakeBoardId": "Board-ID",
2919
2924
  "intakeBoardIdHelp": "Das Board, Projekt oder die Warteschlange, auf die dieser Tracker die Aufnahme eingrenzt. Das Format gibt der Tracker vor.",
@@ -384,6 +384,7 @@
384
384
  "intake": "Issue intake",
385
385
  "intakeHint": "Each run picks one matching open issue from the tracker and works it end to end.",
386
386
  "intakeNoSources": "Connect a task source first to pull issues from it.",
387
+ "intakeNoIntakeSources": "A task source is connected, but none of the connected sources can run a scheduled issue search yet.",
387
388
  "intakeGithubRepo": "Repository",
388
389
  "intakeBoardId": "Board id",
389
390
  "intakeBoardIdHelp": "The board, project or queue this tracker scopes intake to. Its format is defined by the tracker.",
@@ -1534,6 +1535,16 @@
1534
1535
  "oauthNotConnected": "Connect this board to it from the Infrastructure window. A deployment with no ENCRYPTION_KEY has nowhere to keep a grant, so an operator has to set that first.",
1535
1536
  "oauthTokenFailed": "Reconnect it from the Infrastructure window, or wait out the vendor's outage.",
1536
1537
  "overBudget": "Trim what the agent declares, so one run can carry all of it."
1538
+ },
1539
+ "observed": {
1540
+ "ready": "started",
1541
+ "readyTools": "{count} tools",
1542
+ "readyNoTools": "started, no tools",
1543
+ "failed": "failed to start",
1544
+ "needsAuth": "needs authorization",
1545
+ "unknown": "state unresolved",
1546
+ "notLoaded": "never loaded",
1547
+ "unattributed": "The agent CLI reported a server this step did not wire: {id}."
1537
1548
  }
1538
1549
  },
1539
1550
  "adherence": {
@@ -3010,27 +3021,21 @@
3010
3021
  "linearTeamSearchPlaceholder": "Search teams…"
3011
3022
  },
3012
3023
  "vendor": {
3013
- "github": "GitHub Issues",
3014
- "jira": "Jira",
3015
- "linear": "Linear"
3024
+ "github": "GitHub Issues"
3016
3025
  },
3017
3026
  "linking": {
3018
3027
  "heading": "Link issues as context",
3019
3028
  "description": "When a source is offered you can import its issues and attach them to a task, so agents see the issue description and comments while implementing. This is independent of the filing tracker above.",
3020
- "github": {
3021
- "available": "Rides your installed GitHub App — no credentials needed.",
3022
- "unavailable": "Install the GitHub App (Integrations → GitHub) to offer this source."
3023
- },
3024
3029
  "checkSetup": "Check setup",
3025
- "install": "Install",
3026
3030
  "connected": "Connected.",
3027
- "jira": {
3028
- "connectHint": "Connect with a Jira account and API token."
3029
- },
3030
- "linear": {
3031
- "connectHint": "Connect with a Linear personal API key."
3031
+ "connect": "Connect",
3032
+ "state": {
3033
+ "ridesConnected": "Rides this workspace's {provider} connection, so it needs no credentials of its own.",
3034
+ "ridesMissing": "Connect {provider} under Integrations to offer this source.",
3035
+ "notConnected": "Not connected yet."
3032
3036
  },
3033
- "connect": "Connect"
3037
+ "connectProvider": "Connect {provider}",
3038
+ "none": "This deployment has no task sources configured."
3034
3039
  },
3035
3040
  "writeback": {
3036
3041
  "heading": "Writeback",
@@ -345,6 +345,7 @@
345
345
  "intake": "Admisión de incidencias",
346
346
  "intakeHint": "Cada ejecución toma una incidencia abierta que coincide del rastreador y la resuelve de principio a fin.",
347
347
  "intakeNoSources": "Primero conecta una fuente de tareas para extraer incidencias de ella.",
348
+ "intakeNoIntakeSources": "Hay una fuente de tareas conectada, pero ninguna de las fuentes conectadas puede ejecutar todavía una búsqueda programada de incidencias.",
348
349
  "intakeGithubRepo": "Repositorio",
349
350
  "intakeBoardId": "ID del tablero",
350
351
  "intakeBoardIdHelp": "El tablero, proyecto o cola al que este rastreador limita la admisión. El formato lo define el rastreador.",
@@ -1443,6 +1444,16 @@
1443
1444
  "oauthNotConnected": "Conecta este tablero con él desde la ventana de Infraestructura. Un despliegue sin ENCRYPTION_KEY no tiene dónde guardar una concesión, así que un operador debe configurarla primero.",
1444
1445
  "oauthTokenFailed": "Vuelve a conectarlo desde la ventana de Infraestructura, o espera a que pase la caída del proveedor.",
1445
1446
  "overBudget": "Recorta lo que declara el agente, para que una ejecución pueda llevarlo todo."
1447
+ },
1448
+ "observed": {
1449
+ "ready": "iniciado",
1450
+ "readyTools": "{count} herramientas",
1451
+ "readyNoTools": "iniciado, sin herramientas",
1452
+ "failed": "no arrancó",
1453
+ "needsAuth": "requiere autorización",
1454
+ "unknown": "estado sin determinar",
1455
+ "notLoaded": "nunca se cargó",
1456
+ "unattributed": "La CLI del agente informó de un servidor que este paso no conectó: {id}."
1446
1457
  }
1447
1458
  },
1448
1459
  "adherence": {
@@ -2759,27 +2770,21 @@
2759
2770
  "linearTeamSearchPlaceholder": "Buscar equipos…"
2760
2771
  },
2761
2772
  "vendor": {
2762
- "github": "GitHub Issues",
2763
- "jira": "Jira",
2764
- "linear": "Linear"
2773
+ "github": "GitHub Issues"
2765
2774
  },
2766
2775
  "linking": {
2767
2776
  "heading": "Vincular incidencias como contexto",
2768
2777
  "description": "Cuando se ofrece una fuente, puedes importar sus incidencias y adjuntarlas a una tarea, para que los agentes vean la descripción de la incidencia y los comentarios mientras implementan. Esto es independiente del gestor de registro de arriba.",
2769
- "github": {
2770
- "available": "Usa tu GitHub App instalada: no se necesitan credenciales.",
2771
- "unavailable": "Instala la GitHub App (Integraciones → GitHub) para ofrecer esta fuente."
2772
- },
2773
2778
  "checkSetup": "Comprobar configuración",
2774
- "install": "Instalar",
2775
2779
  "connected": "Conectado.",
2776
- "jira": {
2777
- "connectHint": "Conecta con una cuenta de Jira y un token de API."
2778
- },
2779
- "linear": {
2780
- "connectHint": "Conecta con una clave de API personal de Linear."
2780
+ "connect": "Conectar",
2781
+ "state": {
2782
+ "ridesConnected": "Usa la conexión de {provider} de este espacio de trabajo, así que no necesita credenciales propias.",
2783
+ "ridesMissing": "Conecta {provider} en Integraciones para ofrecer esta fuente.",
2784
+ "notConnected": "Aún sin conectar."
2781
2785
  },
2782
- "connect": "Conectar"
2786
+ "connectProvider": "Conectar {provider}",
2787
+ "none": "Este despliegue no tiene fuentes de tareas configuradas."
2783
2788
  },
2784
2789
  "writeback": {
2785
2790
  "heading": "Escritura de vuelta",