@cat-factory/app 0.215.0 → 0.215.2

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.
@@ -10,7 +10,6 @@ import type {
10
10
  GitHubRepo,
11
11
  RepoTreeEntry,
12
12
  VcsConnectOption,
13
- VcsProvider,
14
13
  } from '~/types/domain'
15
14
  import { useSingleFlightProbe } from '~/composables/useSingleFlightProbe'
16
15
  import { useUpsertList } from '~/composables/useUpsertList'
@@ -19,7 +18,7 @@ import { useServicesStore } from '~/stores/services'
19
18
  import { pullKey, type GitHubStoreContext } from '~/stores/github/context'
20
19
  import { createGitHubConnectionActions } from '~/stores/github/connection'
21
20
  import { createGitHubRepoActions } from '~/stores/github/repoActions'
22
- import { createVcsConnectActions } from '~/stores/github/vcsConnect'
21
+ import { createVcsConnectActions, createVcsProviderViews } from '~/stores/github/vcsConnect'
23
22
 
24
23
  /**
25
24
  * GitHub integration state: the workspace's App installation, the projected
@@ -63,26 +62,6 @@ export const useGitHubStore = defineStore('github', () => {
63
62
  const syncing = ref(false)
64
63
 
65
64
  const connected = computed(() => connection.value !== null)
66
- /**
67
- * The provider backing the current connection. Presentation (labels, icons, host/URL shapes)
68
- * keys off this; a connection from a backend predating the discriminator is a GitHub App one.
69
- */
70
- const provider = computed<VcsProvider>(() => connection.value?.provider ?? 'github')
71
- /** Whether the deployment can serve a GitHub App connect / a per-workspace GitLab PAT connect. */
72
- const canConnectGitHubApp = computed(() =>
73
- connectOptions.value.some((o) => o.provider === 'github' && o.method === 'app'),
74
- )
75
- const canConnectGitLabPat = computed(() =>
76
- connectOptions.value.some((o) => o.provider === 'gitlab' && o.method === 'pat'),
77
- )
78
- /**
79
- * The single provider this deployment can connect, or null when it offers several (or none) —
80
- * what the connect copy keys off so a one-provider deployment never says "choose a provider".
81
- */
82
- const soleConnectProvider = computed<VcsProvider | null>(() => {
83
- const providers = new Set(connectOptions.value.map((o) => o.provider))
84
- return providers.size === 1 ? [...providers][0]! : null
85
- })
86
65
  /** Whether cat-factory can create repos under the connected account itself. */
87
66
  const canCreateRepos = computed(() => connection.value?.canCreateRepos === true)
88
67
  /**
@@ -219,6 +198,9 @@ export const useGitHubStore = defineStore('github', () => {
219
198
  const connectionActions = createGitHubConnectionActions(context)
220
199
  const repoActions = createGitHubRepoActions(context)
221
200
  const vcsConnectActions = createVcsConnectActions(context)
201
+ // The derived "which provider" questions, beside the connect actions that populate what they
202
+ // read (see `createVcsProviderViews` for why `provider` and `surfaceProvider` differ).
203
+ const providerViews = createVcsProviderViews(context)
222
204
 
223
205
  /**
224
206
  * Drop the per-workspace projection + connection state (called on workspace switch)
@@ -254,10 +236,7 @@ export const useGitHubStore = defineStore('github', () => {
254
236
  loading,
255
237
  syncing,
256
238
  connected,
257
- provider,
258
- canConnectGitHubApp,
259
- canConnectGitLabPat,
260
- soleConnectProvider,
239
+ ...providerViews,
261
240
  canCreateRepos,
262
241
  missingWorkflowsPermission,
263
242
  repoFor,
@@ -0,0 +1,101 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import {
3
+ appInstallationManageUrl,
4
+ newRepoUrl,
5
+ VCS_PROVIDER_ICONS,
6
+ VCS_PROVIDER_LABELS,
7
+ VCS_PROVIDER_TOKEN_URLS,
8
+ } from './vcs'
9
+ import type { GitHubConnection, VcsProvider } from '~/types/domain'
10
+
11
+ /**
12
+ * The one place VCS presentation switches on the provider. What is pinned here is the pair of
13
+ * decisions a component must never make for itself: which affordances belong to a GitHub-App
14
+ * installation (and therefore vanish on a pasted token), and which host page a manual
15
+ * repo-creation link may open, including the hosts it must refuse to guess at.
16
+ */
17
+ const connection = (over: Partial<GitHubConnection> = {}): GitHubConnection => ({
18
+ installationId: 42,
19
+ accountLogin: 'acme',
20
+ targetType: 'User',
21
+ connectedAt: 0,
22
+ provider: 'github',
23
+ method: 'app',
24
+ canCreateRepos: false,
25
+ canManageWorkflows: true,
26
+ ...over,
27
+ })
28
+
29
+ describe('appInstallationManageUrl', () => {
30
+ it('links a personal App installation to the user settings page', () => {
31
+ expect(appInstallationManageUrl(connection())).toBe(
32
+ 'https://github.com/settings/installations/42',
33
+ )
34
+ })
35
+
36
+ it('links an organization App installation to the org settings page', () => {
37
+ expect(appInstallationManageUrl(connection({ targetType: 'Organization' }))).toBe(
38
+ 'https://github.com/organizations/acme/settings/installations/42',
39
+ )
40
+ })
41
+
42
+ // The whole point of the helper: a pasted token has no installation, so there is no page to
43
+ // send the user to. Both modals used to build the github.com URL from the connection
44
+ // unconditionally, which put a "Grant the App access" button that 404s in front of every
45
+ // GitLab-connected workspace.
46
+ it('has no URL for a PAT connection, whatever its provider', () => {
47
+ expect(
48
+ appInstallationManageUrl(connection({ provider: 'gitlab', method: 'pat' })),
49
+ ).toBeUndefined()
50
+ expect(
51
+ appInstallationManageUrl(connection({ provider: 'github', method: 'pat' })),
52
+ ).toBeUndefined()
53
+ })
54
+
55
+ it('has no URL when there is no connection', () => {
56
+ expect(appInstallationManageUrl(null)).toBeUndefined()
57
+ })
58
+ })
59
+
60
+ describe('newRepoUrl', () => {
61
+ it('prefills the GitHub new-repository form with everything the caller knows', () => {
62
+ const url = new URL(
63
+ newRepoUrl('github', { owner: 'acme', name: 'api', private: true }) ?? 'about:blank',
64
+ )
65
+ expect(url.origin + url.pathname).toBe('https://github.com/new')
66
+ expect(url.searchParams.get('owner')).toBe('acme')
67
+ expect(url.searchParams.get('name')).toBe('api')
68
+ expect(url.searchParams.get('visibility')).toBe('private')
69
+ })
70
+
71
+ it('omits what the caller has not filled in yet, and marks a public repo public', () => {
72
+ const url = new URL(newRepoUrl('github', { name: '', private: false }) ?? 'about:blank')
73
+ expect(url.searchParams.has('owner')).toBe(false)
74
+ expect(url.searchParams.has('name')).toBe(false)
75
+ expect(url.searchParams.get('visibility')).toBe('public')
76
+ })
77
+
78
+ // A deployment may be bound to any self-hosted GitLab and nothing on the wire names its web
79
+ // host yet, so there is no page this can honestly open. Withheld rather than guessed at:
80
+ // gitlab.com would look like it worked, and the user would create the project on a server
81
+ // the bootstrap run never pushes to.
82
+ it('withholds a page for GitLab, whose instance the SPA cannot name', () => {
83
+ expect(newRepoUrl('gitlab', { name: 'api', private: false })).toBeUndefined()
84
+ })
85
+
86
+ it('withholds a page when no provider is resolved', () => {
87
+ expect(newRepoUrl(null, { name: 'api', private: false })).toBeUndefined()
88
+ })
89
+ })
90
+
91
+ describe('provider presentation maps', () => {
92
+ const providers: VcsProvider[] = ['github', 'gitlab']
93
+
94
+ // Each map is an exhaustive Record, so this only guards against an entry left empty: the
95
+ // typecheck already fails when a provider joins the union with no row.
96
+ it.each(providers)('has a label, icon and token URL for %s', (provider) => {
97
+ expect(VCS_PROVIDER_LABELS[provider]).toBeTruthy()
98
+ expect(VCS_PROVIDER_ICONS[provider]).toMatch(/^i-lucide-/)
99
+ expect(VCS_PROVIDER_TOKEN_URLS[provider]).toMatch(/^https:\/\//)
100
+ })
101
+ })
package/app/utils/vcs.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { VcsProvider } from '~/types/domain'
1
+ import type { GitHubConnection, VcsProvider } from '~/types/domain'
2
2
 
3
3
  // ---------------------------------------------------------------------------
4
4
  // Shared VCS provider presentation. The platform's repo DATA is provider-neutral (one
@@ -29,3 +29,65 @@ export const VCS_PROVIDER_TOKEN_URLS: Record<VcsProvider, string> = {
29
29
  github: 'https://github.com/settings/tokens/new',
30
30
  gitlab: 'https://gitlab.com/-/user_settings/personal_access_tokens',
31
31
  }
32
+
33
+ /**
34
+ * Where a user creates a repository by hand, for the flows that need one to exist before a run
35
+ * can target it, or `null` where the SPA cannot name the instance the workspace is connected
36
+ * to, in which case the affordance is WITHHELD rather than pointed somewhere plausible.
37
+ *
38
+ * `gitlab` is null for that reason: a deployment may be bound to any self-hosted instance and
39
+ * nothing on the wire carries its web host yet (the connection is the proposed carrier; see
40
+ * the initiative tracker's slice 5). `https://gitlab.com/projects/new` would be a guess about
41
+ * which server the user's projects live on, and the cost of being wrong is not a dead link: a
42
+ * project created on the wrong instance looks like success until the bootstrap push cannot
43
+ * find it. This is the same rule the callers already apply when no provider is resolved at
44
+ * all, so the two cases collapse into {@link newRepoUrl} returning `undefined`.
45
+ *
46
+ * A `Record` rather than a switch so a provider joining the union has to state its answer.
47
+ */
48
+ const NEW_REPO_PAGES: Record<VcsProvider, string | null> = {
49
+ github: 'https://github.com/new',
50
+ gitlab: null,
51
+ }
52
+
53
+ /**
54
+ * The App installation's settings page, where a user grants it access to a repository it
55
+ * can't see yet — or `undefined` when the connection is not a GitHub-App one.
56
+ *
57
+ * A pasted PAT has no installation and no such page: what it can reach is decided by the
58
+ * token's scope and the user's project membership on the host, so there is nothing to link
59
+ * to and the callers drop the affordance rather than pointing at a URL that 404s. Keyed on the
60
+ * connection's own `method` (see the contract) rather than on `provider`, and asked as
61
+ * `=== 'app'` so anything that is not an App installation withholds the link.
62
+ */
63
+ export function appInstallationManageUrl(connection: GitHubConnection | null): string | undefined {
64
+ if (!connection || connection.method !== 'app') return undefined
65
+ return connection.targetType === 'Organization'
66
+ ? `https://github.com/organizations/${connection.accountLogin}/settings/installations/${connection.installationId}`
67
+ : `https://github.com/settings/installations/${connection.installationId}`
68
+ }
69
+
70
+ /**
71
+ * The host's new-repository page for a manual create, or `undefined` where there is no page
72
+ * this deployment can honestly send the user to (see {@link NEW_REPO_PAGES}), including a
73
+ * null `provider`, which is what a surface rendering before anything is connected has when
74
+ * the deployment offers several. A caller that gets `undefined` hides the affordance.
75
+ *
76
+ * GitHub's form is the only one that takes a prefill, so what the bootstrap flow already
77
+ * knows is carried over and the user creates the right repo in one click. `visibility` is
78
+ * always stated: the caller's toggle has an answer either way, unlike the text fields.
79
+ */
80
+ export function newRepoUrl(
81
+ provider: VcsProvider | null,
82
+ prefill: { owner?: string; name?: string; description?: string; private: boolean },
83
+ ): string | undefined {
84
+ const page = provider ? NEW_REPO_PAGES[provider] : null
85
+ if (page === null) return undefined
86
+ if (provider !== 'github') return page
87
+ const params = new URLSearchParams()
88
+ if (prefill.owner) params.set('owner', prefill.owner)
89
+ if (prefill.name) params.set('name', prefill.name)
90
+ if (prefill.description) params.set('description', prefill.description)
91
+ params.set('visibility', prefill.private ? 'private' : 'public')
92
+ return `${page}?${params.toString()}`
93
+ }
@@ -3133,18 +3133,13 @@
3133
3133
  },
3134
3134
  "addService": {
3135
3135
  "title": "Einen Service aus einem Repository hinzufügen",
3136
- "intro": "Wählen Sie ein bestehendes GitHub-Repository, um es als Board-Service hinzuzufügen. Kein Bootstrapping: Das Repo wird unverändert mit einem neuen Service-Frame verknüpft, und Aufgaben, die Sie darauf ausführen, zielen auf dieses Repo.",
3137
- "connectFirst": "Verbinden Sie diesen Workspace zuerst mit GitHub. Verknüpfen Sie eine Installation, auf der die App bereits ist, oder installieren Sie sie.",
3138
3136
  "repository": "Repository",
3139
- "repositoryHint": "Repositorys, auf die die GitHub App zugreifen kann. Ihres nicht dabei? Gewähren Sie der App unten Zugriff und aktualisieren Sie dann.",
3140
3137
  "repoType": "Repository-Typ",
3141
3138
  "repoTypeHint": "Was dieses Repo ist: ein Backend-Service, eine Frontend-App, eine gemeinsame Bibliothek oder ein Dokumenten-Repository (nur Docs/Spikes).",
3142
- "noReposAvailable": "Noch keine Repositorys verfügbar. Gewähren Sie der App unten Zugriff auf eines und aktualisieren Sie dann.",
3143
3139
  "searchPlaceholder": "Repositorys nach Eigentümer oder Name durchsuchen…",
3144
3140
  "searchMinChars": "Geben Sie mindestens {min} Zeichen ein, um zu suchen. | Geben Sie mindestens {min} Zeichen ein, um zu suchen.",
3145
3141
  "noMatches": "Keine Repositorys für {query} gefunden.",
3146
3142
  "clearSelection": "Auswahl aufheben",
3147
- "showingCount": "{shown} von {total} Repositorys werden angezeigt.",
3148
3143
  "repoLabel": {
3149
3144
  "private": " (privat)",
3150
3145
  "monorepo": " · Monorepo",
@@ -3161,7 +3156,6 @@
3161
3156
  "addedConfigure": "{title} hinzugefügt, konfigurieren Sie es",
3162
3157
  "grantAccess": "Der App Zugriff auf ein Repo gewähren",
3163
3158
  "grantAccessTitle": "Öffnen Sie die Installationseinstellungen der App, um ihr Zugriff auf ein Repository zu gewähren",
3164
- "refreshList": "Liste aktualisieren",
3165
3159
  "done": "Fertig",
3166
3160
  "donePendingHint": "Füge zuerst die ausgewählten Services hinzu oder hebe die Auswahl auf – sonst werden diese Auswahlen verworfen.",
3167
3161
  "add": "Service hinzufügen",
@@ -4215,13 +4209,6 @@
4215
4209
  "tooLong": "Darf höchstens 100 Zeichen lang sein."
4216
4210
  }
4217
4211
  },
4218
- "intro": {
4219
- "canCreate": "Erstellen Sie ein leeres GitHub-Repository und lassen Sie es dann von einem Bootstrapper-Agenten in einem Sandbox-Container befüllen — entweder durch Anpassen einer Ihrer Referenzarchitekturen oder von Grund auf nach einem freien Prompt. cat-factory pusht den initialen Commit in dieses Repo; für dieses Konto kann es das Repository auch für Sie erstellen.",
4220
- "manual": "Erstellen Sie ein leeres GitHub-Repository und lassen Sie es dann von einem Bootstrapper-Agenten in einem Sandbox-Container befüllen — entweder durch Anpassen einer Ihrer Referenzarchitekturen oder von Grund auf nach einem freien Prompt. cat-factory pusht den initialen Commit in dieses Repo; Sie erstellen das Repository (ein Klick unten), sodass keine Repo-Erstellungsberechtigung nötig ist."
4221
- },
4222
- "github": {
4223
- "prompt": "Verbinden Sie diesen Workspace mit GitHub, bevor Sie bootstrappen; ein Lauf pusht in ein Repository. Verknüpfen Sie eine Installation, auf der die App bereits ist, oder installieren Sie sie."
4224
- },
4225
4212
  "section": {
4226
4213
  "newRepo": "Neues Repository"
4227
4214
  },
@@ -4250,9 +4237,7 @@
4250
4237
  },
4251
4238
  "createRepo": {
4252
4239
  "now": "Repository erstellen",
4253
- "onGitHub": "Auf GitHub erstellen",
4254
- "titleNow": "Das Repository jetzt erstellen",
4255
- "titleGitHub": "GitHubs Seite für neue Repositorys vorausgefüllt öffnen"
4240
+ "titleNow": "Das Repository jetzt erstellen"
4256
4241
  },
4257
4242
  "grantAccess": {
4258
4243
  "label": "Der App Zugriff auf dieses Repo gewähren",
@@ -4294,7 +4279,6 @@
4294
4279
  "title": "Referenzarchitekturen",
4295
4280
  "add": "Hinzufügen",
4296
4281
  "pickRepo": {
4297
- "label": "Ein bestehendes GitHub-Repo wählen",
4298
4282
  "description": "Wählen Sie ein Repo, auf das Sie Zugriff haben, um Owner und Name auszufüllen, oder geben Sie sie unten manuell ein.",
4299
4283
  "placeholder": "owner/name"
4300
4284
  },
@@ -6371,6 +6355,22 @@
6371
6355
  "titleAny": "cat-factory mit Ihren Repositorys verbinden",
6372
6356
  "intro": "cat-factory funktioniert, indem es Pull Requests in Ihren Repositorys öffnet. Verbinden Sie Ihren Repository-Anbieter, um fortzufahren."
6373
6357
  },
6358
+ "addService": {
6359
+ "intro": "Wählen Sie ein bestehendes {provider}-Repository, um es als Board-Service hinzuzufügen. Kein Bootstrapping: Das Repo wird unverändert mit einem neuen Service-Frame verknüpft, und Aufgaben, die Sie darauf ausführen, zielen auf dieses Repo.",
6360
+ "introAny": "Wählen Sie ein bestehendes Repository, um es als Board-Service hinzuzufügen. Kein Bootstrapping: Das Repo wird unverändert mit einem neuen Service-Frame verknüpft, und Aufgaben, die Sie darauf ausführen, zielen auf dieses Repo.",
6361
+ "connectFirst": "Verbinden Sie diesen Workspace zuerst mit einem Repository-Host, und wählen Sie dann ein Repository zum Hinzufügen aus.",
6362
+ "repositoryHintApp": "Repositorys, auf die die GitHub App zugreifen kann. Ihres nicht dabei? Gewähren Sie der App unten Zugriff und suchen Sie dann erneut.",
6363
+ "repositoryHintToken": "Repositorys, die Ihr {provider}-Token erreichen kann. Ihres nicht dabei? Prüfen Sie den Geltungsbereich des Tokens und Ihren Zugriff auf das Projekt, und suchen Sie dann erneut."
6364
+ },
6365
+ "bootstrap": {
6366
+ "connectPrompt": "Verbinden Sie diesen Workspace mit einem Repository-Host, bevor Sie bootstrappen; ein Lauf pusht in ein Repository.",
6367
+ "createRepoOn": "Auf {provider} erstellen",
6368
+ "createRepoTitle": "Seite für neue Repositorys bei {provider} öffnen",
6369
+ "introCanCreate": "Erstellen Sie ein leeres {provider}-Repository und lassen Sie es dann von einem Bootstrapper-Agenten in einem Sandbox-Container befüllen, entweder durch Anpassen einer Ihrer Referenzarchitekturen oder von Grund auf nach einem freien Prompt. cat-factory pusht den initialen Commit in dieses Repo; für dieses Konto kann es das Repository auch für Sie erstellen.",
6370
+ "introManual": "Erstellen Sie ein leeres {provider}-Repository und lassen Sie es dann von einem Bootstrapper-Agenten in einem Sandbox-Container befüllen, entweder durch Anpassen einer Ihrer Referenzarchitekturen oder von Grund auf nach einem freien Prompt. cat-factory pusht den initialen Commit in dieses Repo; Sie erstellen das Repository (ein Klick unten), sodass keine Repo-Erstellungsberechtigung nötig ist.",
6371
+ "introManualAny": "Erstellen Sie ein leeres Repository bei Ihrem Repository-Host und lassen Sie es dann von einem Bootstrapper-Agenten in einem Sandbox-Container befüllen, entweder durch Anpassen einer Ihrer Referenzarchitekturen oder von Grund auf nach einem freien Prompt. cat-factory pusht den initialen Commit in dieses Repo; Sie erstellen das Repository selbst, sodass keine Repo-Erstellungsberechtigung nötig ist.",
6372
+ "archPickRepo": "Ein bestehendes {provider}-Repo wählen"
6373
+ },
6374
6374
  "branchProtection": {
6375
6375
  "heading": "Schutz des Standard-Branch",
6376
6376
  "body": "Agenten-Ausführungen pushen mit einem Zugang, der in jedes abgedeckte Repository schreiben darf. Nichts hier kann verhindern, dass eine kompromittierte Ausführung direkt auf einen Standard-Branch pusht oder ihren eigenen Pull Request über die API des Hosts merged — beides deckt nur der Branch-Schutz beim Host ab, und den richtest du selbst ein. Diese Prüfung zeigt, ob er vorhanden ist.",
@@ -3890,13 +3890,9 @@
3890
3890
  },
3891
3891
  "addService": {
3892
3892
  "title": "Add a service from a repository",
3893
- "intro": "Pick an existing GitHub repository to add as a board service. No bootstrapping: the repo is linked to a new service frame as-is, and tasks you run on it target that repo.",
3894
- "connectFirst": "Connect this workspace to GitHub first. Link an installation the App is already on, or install it.",
3895
3893
  "repository": "Repository",
3896
- "repositoryHint": "Repositories the GitHub App can access. Don't see yours? Grant the App access below, then refresh.",
3897
3894
  "repoType": "Repository type",
3898
3895
  "repoTypeHint": "What this repo is: a backend service, a frontend app, a shared library, or a document repository (docs/spikes only).",
3899
- "noReposAvailable": "No repositories available yet. Grant the App access to one below, then refresh.",
3900
3896
  "searchPlaceholder": "Search repositories by owner or name…",
3901
3897
  "searchMinChars": "Type at least {min} character to search. | Type at least {min} characters to search.",
3902
3898
  "@searchMinChars": {
@@ -3904,7 +3900,6 @@
3904
3900
  },
3905
3901
  "noMatches": "No repositories found for {query}.",
3906
3902
  "clearSelection": "Clear selection",
3907
- "showingCount": "Showing {shown} of {total} repositories.",
3908
3903
  "repoLabel": {
3909
3904
  "private": " (private)",
3910
3905
  "monorepo": " · monorepo",
@@ -3924,7 +3919,6 @@
3924
3919
  "addedConfigure": "{title} added, configure it",
3925
3920
  "grantAccess": "Grant the App access to a repo",
3926
3921
  "grantAccessTitle": "Open the App's installation settings to grant it access to a repository",
3927
- "refreshList": "Refresh list",
3928
3922
  "done": "Done",
3929
3923
  "donePendingHint": "Add your selected services first, or clear the selection — otherwise those picks are discarded.",
3930
3924
  "add": "Add service",
@@ -5974,13 +5968,6 @@
5974
5968
  "tooLong": "Must be 100 characters or fewer."
5975
5969
  }
5976
5970
  },
5977
- "intro": {
5978
- "canCreate": "Create an empty GitHub repository, then let a bootstrapper agent populate it in a sandbox container, either by adapting one of your reference architectures or from scratch following a freeform prompt. cat-factory pushes the initial commit into that repo; for this account it can create the repository for you too.",
5979
- "manual": "Create an empty GitHub repository, then let a bootstrapper agent populate it in a sandbox container, either by adapting one of your reference architectures or from scratch following a freeform prompt. cat-factory pushes the initial commit into that repo; you create the repository (one click below), so it needs no repo-creation permission."
5980
- },
5981
- "github": {
5982
- "prompt": "Connect this workspace to GitHub before bootstrapping; a run pushes into a repository. Link an installation the App is already on, or install it."
5983
- },
5984
5971
  "section": {
5985
5972
  "newRepo": "New repository"
5986
5973
  },
@@ -6009,9 +5996,7 @@
6009
5996
  },
6010
5997
  "createRepo": {
6011
5998
  "now": "Create repository",
6012
- "onGitHub": "Create on GitHub",
6013
- "titleNow": "Create the repository now",
6014
- "titleGitHub": "Open GitHub's new-repository page, prefilled"
5999
+ "titleNow": "Create the repository now"
6015
6000
  },
6016
6001
  "grantAccess": {
6017
6002
  "label": "Grant the App access to this repo",
@@ -6053,7 +6038,6 @@
6053
6038
  "title": "Reference architectures",
6054
6039
  "add": "Add",
6055
6040
  "pickRepo": {
6056
- "label": "Pick an existing GitHub repo",
6057
6041
  "description": "Choose a repo you can access to fill in its owner and name, or enter them manually below.",
6058
6042
  "placeholder": "owner/name"
6059
6043
  },
@@ -6581,6 +6565,22 @@
6581
6565
  "titleAny": "Connect cat-factory to your repositories",
6582
6566
  "intro": "cat-factory works by opening pull requests on your repositories. Connect your repository host to continue."
6583
6567
  },
6568
+ "addService": {
6569
+ "intro": "Pick an existing {provider} repository to add as a board service. No bootstrapping: the repo is linked to a new service frame as-is, and tasks you run on it target that repo.",
6570
+ "introAny": "Pick an existing repository to add as a board service. No bootstrapping: the repo is linked to a new service frame as-is, and tasks you run on it target that repo.",
6571
+ "connectFirst": "Connect this workspace to a repository host first, then pick a repository to add.",
6572
+ "repositoryHintApp": "Repositories the GitHub App can access. Don't see yours? Grant the App access below, then search again.",
6573
+ "repositoryHintToken": "Repositories your {provider} token can reach. Don't see yours? Check the token's scope and your access to the project, then search again."
6574
+ },
6575
+ "bootstrap": {
6576
+ "connectPrompt": "Connect this workspace to a repository host before bootstrapping; a run pushes into a repository.",
6577
+ "createRepoOn": "Create on {provider}",
6578
+ "createRepoTitle": "Open {provider}'s new-repository page",
6579
+ "introCanCreate": "Create an empty {provider} repository, then let a bootstrapper agent populate it in a sandbox container, either by adapting one of your reference architectures or from scratch following a freeform prompt. cat-factory pushes the initial commit into that repo; for this account it can create the repository for you too.",
6580
+ "introManual": "Create an empty {provider} repository, then let a bootstrapper agent populate it in a sandbox container, either by adapting one of your reference architectures or from scratch following a freeform prompt. cat-factory pushes the initial commit into that repo; you create the repository (one click below), so it needs no repo-creation permission.",
6581
+ "introManualAny": "Create an empty repository on your repository host, then let a bootstrapper agent populate it in a sandbox container, either by adapting one of your reference architectures or from scratch following a freeform prompt. cat-factory pushes the initial commit into that repo; you create the repository yourself, so it needs no repo-creation permission.",
6582
+ "archPickRepo": "Pick an existing {provider} repo"
6583
+ },
6584
6584
  "branchProtection": {
6585
6585
  "heading": "Default-branch protection",
6586
6586
  "body": "Agent runs push with a credential that can write to every repository it covers. Nothing here can stop a compromised run pushing straight to a default branch, or merging its own pull request through the host's API — branch protection on the host is what covers both, and it is yours to configure. This checks whether it is in place.",
@@ -3774,16 +3774,11 @@
3774
3774
  },
3775
3775
  "addService": {
3776
3776
  "title": "Añadir un servicio desde un repositorio",
3777
- "intro": "Elige un repositorio de GitHub existente para añadirlo como servicio del tablero. Sin arranque inicial: el repositorio se vincula tal cual a un nuevo marco de servicio, y las tareas que ejecutes en él apuntan a ese repositorio.",
3778
- "connectFirst": "Conecta primero este espacio de trabajo con GitHub. Vincula una instalación en la que la App ya esté, o instálala.",
3779
3777
  "repository": "Repositorio",
3780
- "repositoryHint": "Repositorios a los que la GitHub App puede acceder. ¿No ves el tuyo? Concede acceso a la App abajo y luego actualiza.",
3781
- "noReposAvailable": "Aún no hay repositorios disponibles. Concede acceso a la App a uno abajo y luego actualiza.",
3782
3778
  "searchPlaceholder": "Busca repositorios por propietario o nombre…",
3783
3779
  "searchMinChars": "Escribe al menos {min} carácter para buscar. | Escribe al menos {min} caracteres para buscar.",
3784
3780
  "noMatches": "No se encontraron repositorios para {query}.",
3785
3781
  "clearSelection": "Borrar selección",
3786
- "showingCount": "Mostrando {shown} de {total} repositorios.",
3787
3782
  "repoLabel": {
3788
3783
  "private": " (privado)",
3789
3784
  "monorepo": " · monorepo",
@@ -3800,7 +3795,6 @@
3800
3795
  "addedConfigure": "{title} añadido, configúralo",
3801
3796
  "grantAccess": "Conceder a la App acceso a un repositorio",
3802
3797
  "grantAccessTitle": "Abrir la configuración de instalación de la App para concederle acceso a un repositorio",
3803
- "refreshList": "Actualizar lista",
3804
3798
  "done": "Listo",
3805
3799
  "donePendingHint": "Añade primero los servicios seleccionados o borra la selección; de lo contrario, esas elecciones se descartan.",
3806
3800
  "add": "Añadir servicio",
@@ -5710,13 +5704,6 @@
5710
5704
  "tooLong": "Debe tener 100 caracteres o menos."
5711
5705
  }
5712
5706
  },
5713
- "intro": {
5714
- "canCreate": "Crea un repositorio de GitHub vacío y deja que un agente inicializador lo poble en un contenedor de pruebas, ya sea adaptando una de tus arquitecturas de referencia o desde cero siguiendo un prompt libre. cat-factory envía el commit inicial a ese repositorio; en esta cuenta también puede crear el repositorio por ti.",
5715
- "manual": "Crea un repositorio de GitHub vacío y deja que un agente inicializador lo poble en un contenedor de pruebas, ya sea adaptando una de tus arquitecturas de referencia o desde cero siguiendo un prompt libre. cat-factory envía el commit inicial a ese repositorio; tú creas el repositorio (con un clic más abajo), por lo que no necesita permiso para crear repositorios."
5716
- },
5717
- "github": {
5718
- "prompt": "Conecta este espacio de trabajo a GitHub antes de inicializar; una ejecución hace push a un repositorio. Vincula una instalación en la que la App ya esté, o instálala."
5719
- },
5720
5707
  "section": {
5721
5708
  "newRepo": "Nuevo repositorio"
5722
5709
  },
@@ -5745,9 +5732,7 @@
5745
5732
  },
5746
5733
  "createRepo": {
5747
5734
  "now": "Crear repositorio",
5748
- "onGitHub": "Crear en GitHub",
5749
- "titleNow": "Crear el repositorio ahora",
5750
- "titleGitHub": "Abrir la página de nuevo repositorio de GitHub, rellenada"
5735
+ "titleNow": "Crear el repositorio ahora"
5751
5736
  },
5752
5737
  "grantAccess": {
5753
5738
  "label": "Conceder a la App acceso a este repositorio",
@@ -5785,7 +5770,6 @@
5785
5770
  "title": "Arquitecturas de referencia",
5786
5771
  "add": "Añadir",
5787
5772
  "pickRepo": {
5788
- "label": "Elige un repositorio de GitHub existente",
5789
5773
  "description": "Elige un repositorio al que tengas acceso para rellenar su propietario y nombre, o introdúcelos manualmente abajo.",
5790
5774
  "placeholder": "owner/name"
5791
5775
  },
@@ -6359,6 +6343,22 @@
6359
6343
  "titleAny": "Conecta cat-factory con tus repositorios",
6360
6344
  "intro": "cat-factory funciona abriendo solicitudes de incorporación de cambios en tus repositorios. Conecta tu proveedor de repositorios para continuar."
6361
6345
  },
6346
+ "addService": {
6347
+ "intro": "Elige un repositorio de {provider} existente para añadirlo como servicio del tablero. Sin arranque inicial: el repositorio se vincula tal cual a un nuevo marco de servicio, y las tareas que ejecutes en él apuntan a ese repositorio.",
6348
+ "introAny": "Elige un repositorio existente para añadirlo como servicio del tablero. Sin arranque inicial: el repositorio se vincula tal cual a un nuevo marco de servicio, y las tareas que ejecutes en él apuntan a ese repositorio.",
6349
+ "connectFirst": "Conecta primero este espacio de trabajo con un host de repositorios y luego elige un repositorio para añadir.",
6350
+ "repositoryHintApp": "Repositorios a los que la GitHub App puede acceder. ¿No ves el tuyo? Concede acceso a la App abajo y vuelve a buscar.",
6351
+ "repositoryHintToken": "Repositorios a los que puede acceder tu token de {provider}. ¿No ves el tuyo? Comprueba el alcance del token y tu acceso al proyecto, y vuelve a buscar."
6352
+ },
6353
+ "bootstrap": {
6354
+ "connectPrompt": "Conecta este espacio de trabajo con un host de repositorios antes de inicializar; una ejecución hace push a un repositorio.",
6355
+ "createRepoOn": "Crear en {provider}",
6356
+ "createRepoTitle": "Abrir la página de nuevo repositorio de {provider}",
6357
+ "introCanCreate": "Crea un repositorio de {provider} vacío y deja que un agente inicializador lo pueble en un contenedor de pruebas, ya sea adaptando una de tus arquitecturas de referencia o desde cero siguiendo un prompt libre. cat-factory envía el commit inicial a ese repositorio; en esta cuenta también puede crear el repositorio por ti.",
6358
+ "introManual": "Crea un repositorio de {provider} vacío y deja que un agente inicializador lo pueble en un contenedor de pruebas, ya sea adaptando una de tus arquitecturas de referencia o desde cero siguiendo un prompt libre. cat-factory envía el commit inicial a ese repositorio; tú creas el repositorio (con un clic más abajo), por lo que no necesita permiso para crear repositorios.",
6359
+ "introManualAny": "Crea un repositorio vacío en tu host de repositorios y deja que un agente inicializador lo pueble en un contenedor de pruebas, ya sea adaptando una de tus arquitecturas de referencia o desde cero siguiendo un prompt libre. cat-factory envía el commit inicial a ese repositorio; tú creas el repositorio por tu cuenta, por lo que no necesita permiso para crear repositorios.",
6360
+ "archPickRepo": "Elige un repositorio de {provider} existente"
6361
+ },
6362
6362
  "branchProtection": {
6363
6363
  "heading": "Protección de la rama predeterminada",
6364
6364
  "body": "Las ejecuciones de agentes hacen push con una credencial que puede escribir en todos los repositorios que cubre. Nada de lo que hay aquí impide que una ejecución comprometida haga push directamente a una rama predeterminada, ni que fusione su propia solicitud de incorporación mediante la API del host: solo la protección de ramas en el host cubre ambos casos, y la configuras tú. Esta comprobación indica si está activa.",
@@ -3774,16 +3774,11 @@
3774
3774
  },
3775
3775
  "addService": {
3776
3776
  "title": "Ajouter un service depuis un dépôt",
3777
- "intro": "Choisissez un dépôt GitHub existant à ajouter comme service du tableau. Sans amorçage : le dépôt est lié tel quel à un nouveau cadre de service, et les tâches que vous y exécutez ciblent ce dépôt.",
3778
- "connectFirst": "Connectez d'abord cet espace de travail à GitHub. Liez une installation sur laquelle l'App est déjà, ou installez-la.",
3779
3777
  "repository": "Dépôt",
3780
- "repositoryHint": "Dépôts auxquels la GitHub App peut accéder. Vous ne voyez pas le vôtre ? Accordez l'accès à l'App ci-dessous, puis actualisez.",
3781
- "noReposAvailable": "Aucun dépôt disponible pour le moment. Accordez l'accès de l'App à l'un d'eux ci-dessous, puis actualisez.",
3782
3778
  "searchPlaceholder": "Rechercher des dépôts par propriétaire ou nom…",
3783
3779
  "searchMinChars": "Saisissez au moins {min} caractère pour rechercher. | Saisissez au moins {min} caractères pour rechercher.",
3784
3780
  "noMatches": "Aucun dépôt trouvé pour {query}.",
3785
3781
  "clearSelection": "Effacer la sélection",
3786
- "showingCount": "Affichage de {shown} dépôts sur {total}.",
3787
3782
  "repoLabel": {
3788
3783
  "private": " (privé)",
3789
3784
  "monorepo": " · monorepo",
@@ -3800,7 +3795,6 @@
3800
3795
  "addedConfigure": "{title} ajouté, configurez-le",
3801
3796
  "grantAccess": "Accorder à l'App l'accès à un dépôt",
3802
3797
  "grantAccessTitle": "Ouvrir les paramètres d'installation de l'App pour lui accorder l'accès à un dépôt",
3803
- "refreshList": "Actualiser la liste",
3804
3798
  "done": "Terminé",
3805
3799
  "donePendingHint": "Ajoutez d'abord les services sélectionnés ou effacez la sélection, sinon ces choix seront perdus.",
3806
3800
  "add": "Ajouter le service",
@@ -5710,13 +5704,6 @@
5710
5704
  "tooLong": "Doit comporter 100 caractères ou moins."
5711
5705
  }
5712
5706
  },
5713
- "intro": {
5714
- "canCreate": "Créez un dépôt GitHub vide, puis laissez un agent d'initialisation le remplir dans un conteneur bac à sable, soit en adaptant l'une de vos architectures de référence, soit à partir de zéro selon un prompt libre. cat-factory pousse le commit initial dans ce dépôt ; pour ce compte, il peut aussi créer le dépôt à votre place.",
5715
- "manual": "Créez un dépôt GitHub vide, puis laissez un agent d'initialisation le remplir dans un conteneur bac à sable, soit en adaptant l'une de vos architectures de référence, soit à partir de zéro selon un prompt libre. cat-factory pousse le commit initial dans ce dépôt ; vous créez le dépôt (en un clic ci-dessous), il n'a donc besoin d'aucune autorisation de création de dépôt."
5716
- },
5717
- "github": {
5718
- "prompt": "Connectez cet espace de travail à GitHub avant l'initialisation ; une exécution pousse dans un dépôt. Liez une installation sur laquelle l'App est déjà présente, ou installez-la."
5719
- },
5720
5707
  "section": {
5721
5708
  "newRepo": "Nouveau dépôt"
5722
5709
  },
@@ -5745,9 +5732,7 @@
5745
5732
  },
5746
5733
  "createRepo": {
5747
5734
  "now": "Créer le dépôt",
5748
- "onGitHub": "Créer sur GitHub",
5749
- "titleNow": "Créer le dépôt maintenant",
5750
- "titleGitHub": "Ouvrir la page de nouveau dépôt de GitHub, préremplie"
5735
+ "titleNow": "Créer le dépôt maintenant"
5751
5736
  },
5752
5737
  "grantAccess": {
5753
5738
  "label": "Accorder à l'App l'accès à ce dépôt",
@@ -5785,7 +5770,6 @@
5785
5770
  "title": "Architectures de référence",
5786
5771
  "add": "Ajouter",
5787
5772
  "pickRepo": {
5788
- "label": "Choisir un dépôt GitHub existant",
5789
5773
  "description": "Choisissez un dépôt auquel vous avez accès pour renseigner son propriétaire et son nom, ou saisissez-les manuellement ci-dessous.",
5790
5774
  "placeholder": "owner/name"
5791
5775
  },
@@ -6359,6 +6343,22 @@
6359
6343
  "titleAny": "Connecter cat-factory à vos dépôts",
6360
6344
  "intro": "cat-factory fonctionne en ouvrant des pull requests sur vos dépôts. Connectez votre hébergeur de dépôts pour continuer."
6361
6345
  },
6346
+ "addService": {
6347
+ "intro": "Choisissez un dépôt {provider} existant à ajouter comme service du tableau. Sans amorçage : le dépôt est lié tel quel à un nouveau cadre de service, et les tâches que vous y exécutez ciblent ce dépôt.",
6348
+ "introAny": "Choisissez un dépôt existant à ajouter comme service du tableau. Sans amorçage : le dépôt est lié tel quel à un nouveau cadre de service, et les tâches que vous y exécutez ciblent ce dépôt.",
6349
+ "connectFirst": "Connectez d'abord cet espace de travail à un hébergeur de dépôts, puis choisissez un dépôt à ajouter.",
6350
+ "repositoryHintApp": "Dépôts auxquels la GitHub App peut accéder. Vous ne voyez pas le vôtre ? Accordez l'accès à l'App ci-dessous, puis relancez la recherche.",
6351
+ "repositoryHintToken": "Dépôts accessibles à votre jeton {provider}. Vous ne voyez pas le vôtre ? Vérifiez la portée du jeton et votre accès au projet, puis relancez la recherche."
6352
+ },
6353
+ "bootstrap": {
6354
+ "connectPrompt": "Connectez cet espace de travail à un hébergeur de dépôts avant l'initialisation ; une exécution pousse dans un dépôt.",
6355
+ "createRepoOn": "Créer sur {provider}",
6356
+ "createRepoTitle": "Ouvrir la page de nouveau dépôt de {provider}",
6357
+ "introCanCreate": "Créez un dépôt {provider} vide, puis laissez un agent d'initialisation le remplir dans un conteneur bac à sable, soit en adaptant l'une de vos architectures de référence, soit à partir de zéro selon un prompt libre. cat-factory pousse le commit initial dans ce dépôt ; pour ce compte, il peut aussi créer le dépôt à votre place.",
6358
+ "introManual": "Créez un dépôt {provider} vide, puis laissez un agent d'initialisation le remplir dans un conteneur bac à sable, soit en adaptant l'une de vos architectures de référence, soit à partir de zéro selon un prompt libre. cat-factory pousse le commit initial dans ce dépôt ; vous créez le dépôt (en un clic ci-dessous), il n'a donc besoin d'aucune autorisation de création de dépôt.",
6359
+ "introManualAny": "Créez un dépôt vide chez votre hébergeur de dépôts, puis laissez un agent d'initialisation le remplir dans un conteneur bac à sable, soit en adaptant l'une de vos architectures de référence, soit à partir de zéro selon un prompt libre. cat-factory pousse le commit initial dans ce dépôt ; vous créez le dépôt vous-même, il n'a donc besoin d'aucune autorisation de création de dépôt.",
6360
+ "archPickRepo": "Choisir un dépôt {provider} existant"
6361
+ },
6362
6362
  "branchProtection": {
6363
6363
  "heading": "Protection de la branche par défaut",
6364
6364
  "body": "Les exécutions d'agents poussent avec un identifiant qui peut écrire dans tous les dépôts qu'il couvre. Rien ici n'empêche une exécution compromise de pousser directement sur une branche par défaut, ni de fusionner sa propre demande de tirage via l'API de l'hôte : seule la protection de branche chez l'hôte couvre les deux cas, et c'est à vous de la configurer. Cette vérification indique si elle est en place.",