@cat-factory/app 0.262.0 → 0.263.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.
@@ -57,6 +57,23 @@ function minterLabel(key: PublicApiKey): string | null {
57
57
  ? t('settings.apiTokens.list.createdByYou')
58
58
  : key.createdByUserId
59
59
  }
60
+
61
+ /**
62
+ * The badge for a key bound to a person's subscription, WHOSE person named.
63
+ *
64
+ * Keys are workspace-scoped and this list is shared, so a colleague's bound key is right here in
65
+ * everyone's panel: a fixed "your subscription" tells every other member that a token they never
66
+ * minted reaches theirs, which is alarming and false. The same comparison {@link minterLabel} makes
67
+ * is available (a binding is always to the minter), so the honest badge names the owner, and falls
68
+ * back to the `usr_*` id for the same reason that function does — there is no user-name lookup here,
69
+ * and an id is not misleading.
70
+ */
71
+ function boundLabel(key: PublicApiKey): string | null {
72
+ if (!key.actsAsUserId) return null
73
+ return key.actsAsUserId === auth.user?.id
74
+ ? t('settings.apiTokens.list.boundToYou')
75
+ : t('settings.apiTokens.list.boundToOther', { user: key.actsAsUserId })
76
+ }
60
77
  const toast = useToast()
61
78
  const { present } = usePipelineErrorToast()
62
79
  const { confirmAction, toastDone } = useConfirmAction()
@@ -70,6 +87,35 @@ const back = useIntegrationBack(open)
70
87
  const label = ref('')
71
88
  // The scope the next minted key will carry; defaults to the safe middle of the ladder.
72
89
  const scope = ref<PublicApiScope>('write')
90
+ // WHO the next key runs as. Two named options rather than an unchecked box, because they are two
91
+ // different credentials with two different blast radii and neither is a mere setting on the other:
92
+ //
93
+ // - `system` (the default): the token belongs to the workspace. Its runs are attributed to nobody
94
+ // and it can reach no personal subscription, so a leaked shared credential can never spend one
95
+ // person's Claude quota. This is what a CI job or a shared integration should hold.
96
+ // - `self`: the token belongs to the person minting it. Its runs are theirs and may unlock their
97
+ // personal Claude / Codex / GLM subscription, with the password sent on each such call.
98
+ //
99
+ // NOT gated on the interface mode, unlike an override field. This whole panel is the Integrations
100
+ // hub's Development surface, reached only by someone already minting an API key, and `scope` next
101
+ // to it is ungated for the same reason. Hiding it in basic mode would leave that person a key that
102
+ // silently cannot run their own models, with nothing on screen to say why.
103
+ type TokenIdentity = 'system' | 'self'
104
+ const identity = ref<TokenIdentity>('system')
105
+ // Nobody to bind on a board with no signed-in user (a dev-open deployment): the server refuses
106
+ // such a mint outright, so the choice is withheld and every key is a system key, which is what
107
+ // that deployment can honestly offer.
108
+ const canBindSelf = computed(() => auth.user !== null && auth.user !== undefined)
109
+ const identityItems = computed(() => [
110
+ { value: 'system' as const, label: t('settings.apiTokens.add.identitySystem') },
111
+ { value: 'self' as const, label: t('settings.apiTokens.add.identitySelf') },
112
+ ])
113
+ /** The help text under the picker, so each option explains ITSELF rather than only its opposite. */
114
+ const identityHelp = computed(() =>
115
+ identity.value === 'self'
116
+ ? t('settings.apiTokens.add.identitySelfHelp')
117
+ : t('settings.apiTokens.add.identitySystemHelp'),
118
+ )
73
119
  const busy = ref(false)
74
120
  // The full raw secret from the most recent create — surfaced once, then dismissed. Never
75
121
  // re-fetchable, so it lives only in this transient ref (not the store).
@@ -97,10 +143,15 @@ async function createToken() {
97
143
  if (!trimmed) return
98
144
  busy.value = true
99
145
  try {
100
- const created = await store.create(trimmed, scope.value)
146
+ const created = await store.create(
147
+ trimmed,
148
+ scope.value,
149
+ canBindSelf.value && identity.value === 'self',
150
+ )
101
151
  newSecret.value = created.secret
102
152
  label.value = ''
103
153
  scope.value = 'write'
154
+ identity.value = 'system'
104
155
  toast.add({
105
156
  title: t('settings.apiTokens.toast.created'),
106
157
  icon: 'i-lucide-check',
@@ -195,6 +246,18 @@ async function revokeToken(key: PublicApiKey) {
195
246
  >
196
247
  {{ scopeLabel(key.scope) }}
197
248
  </UBadge>
249
+ <!-- Always shown, never mode-gated: an existing key can already carry the
250
+ binding, and this is the only place its holder can see that a token they
251
+ are about to hand out reaches a personal subscription. -->
252
+ <UBadge
253
+ v-if="boundLabel(key)"
254
+ color="warning"
255
+ variant="subtle"
256
+ size="sm"
257
+ :data-testid="`api-token-bound-${key.id}`"
258
+ >
259
+ {{ boundLabel(key) }}
260
+ </UBadge>
198
261
  </div>
199
262
  <div class="text-[11px] text-slate-500">
200
263
  {{
@@ -255,6 +318,18 @@ async function revokeToken(key: PublicApiKey) {
255
318
  data-testid="api-token-scope"
256
319
  />
257
320
  </UFormField>
321
+ <UFormField
322
+ v-if="canBindSelf"
323
+ :label="t('settings.apiTokens.add.identity')"
324
+ :help="identityHelp"
325
+ >
326
+ <USelect
327
+ v-model="identity"
328
+ :items="identityItems"
329
+ class="w-full"
330
+ data-testid="api-token-identity"
331
+ />
332
+ </UFormField>
258
333
  <UButton
259
334
  :loading="busy"
260
335
  :disabled="!label.trim()"
@@ -14,6 +14,7 @@ function key(over: Partial<PublicApiKey> = {}): PublicApiKey {
14
14
  createdByUserId: null,
15
15
  createdByKeyId: null,
16
16
  externalIdentity: null,
17
+ actsAsUserId: null,
17
18
  createdAt: 1,
18
19
  lastUsedAt: null,
19
20
  revokedAt: null,
@@ -94,6 +95,21 @@ describe('publicApiKeys store', () => {
94
95
  expect(store.available).toBe(true)
95
96
  })
96
97
 
98
+ it('mints a SYSTEM token unless the caller asks to be bound', async () => {
99
+ // The default decides whose subscription an unattended run may spend, so it is worth an
100
+ // assertion rather than a reading of the signature: a key that silently acted as its minter
101
+ // would put one person's Claude quota behind every integration the workspace hands a token to.
102
+ const body = vi.fn((_body: unknown) => Promise.resolve({ key: key(), secret: 's' }))
103
+ vi.stubGlobal('useApi', () => ({ createPublicApiKey: (_ws: string, b: unknown) => body(b) }))
104
+
105
+ const store = usePublicApiKeysStore()
106
+ await store.create('ci', 'write')
107
+ expect(body).toHaveBeenCalledWith({ label: 'ci', scope: 'write', actsAsSelf: false })
108
+
109
+ await store.create('mine', 'write', true)
110
+ expect(body).toHaveBeenCalledWith({ label: 'mine', scope: 'write', actsAsSelf: true })
111
+ })
112
+
97
113
  it('revoke drops the key from the list', async () => {
98
114
  vi.stubGlobal('useApi', () => ({
99
115
  listPublicApiKeys: () => Promise.resolve({ keys: [key({ id: 'a' }), key({ id: 'b' })] }),
@@ -54,10 +54,18 @@ export const usePublicApiKeysStore = defineStore('publicApiKeys', () => {
54
54
  /**
55
55
  * Mint a key with a permission `scope` (read ⊂ write ⊂ admin). Returns the created record
56
56
  * PLUS the one-time raw secret (shown once).
57
+ *
58
+ * `actsAsSelf` binds the key to the signed-in user's PERSONAL subscriptions, so a headless run
59
+ * it starts can unlock them with the password sent on that call. Passed through rather than
60
+ * defaulted here: the server writes the id off the session, so this is only ever a yes/no.
57
61
  */
58
- async function create(label: string, scope: PublicApiScope): Promise<CreatedPublicApiKey> {
62
+ async function create(
63
+ label: string,
64
+ scope: PublicApiScope,
65
+ actsAsSelf = false,
66
+ ): Promise<CreatedPublicApiKey> {
59
67
  const ws = useWorkspaceStore()
60
- const created = await api.createPublicApiKey(ws.requireId(), { label, scope })
68
+ const created = await api.createPublicApiKey(ws.requireId(), { label, scope, actsAsSelf })
61
69
  // Prepend: the backend lists newest-first, so the freshly minted key belongs at the
62
70
  // top — matching the order a subsequent `load()` would produce.
63
71
  keys.value = [created.key, ...keys.value]
@@ -793,7 +793,9 @@
793
793
  "createdBy": "erstellt von {user}",
794
794
  "createdByYou": "Ihnen",
795
795
  "createdByKey": "API-Schlüssel {id}",
796
- "revoke": "Token widerrufen"
796
+ "revoke": "Token widerrufen",
797
+ "boundToYou": "Ihr Abonnement",
798
+ "boundToOther": "Abonnement von {user}"
797
799
  },
798
800
  "add": {
799
801
  "heading": "Token erstellen",
@@ -802,7 +804,12 @@
802
804
  "labelPlaceholder": "z. B. CI-Pipeline",
803
805
  "scope": "Berechtigung",
804
806
  "scopeHelp": "Was dieses Token darf: nur Lesen, Lesen und Schreiben oder Vollzugriff (der auch das Löschen erlaubt).",
805
- "create": "Token erstellen"
807
+ "create": "Token erstellen",
808
+ "identity": "Läuft als",
809
+ "identitySystem": "Dieser Arbeitsbereich (System-Token)",
810
+ "identitySelf": "Ich (persönliches Token)",
811
+ "identitySystemHelp": "Mit diesem Token gestartete Läufe gehören dem Arbeitsbereich und werden keiner Person zugeordnet. Es kann kein persönliches Claude-/Codex-/GLM-Abonnement nutzen: Eine Aufgabe mit einem solchen Modell wird abgelehnt, statt jemandem in Abwesenheit berechnet zu werden. Für CI und gemeinsam genutzte Integrationen.",
812
+ "identitySelfHelp": "Mit diesem Token gestartete Läufe gelten als Ihre und können Ihr persönliches Claude-/Codex-/GLM-Abonnement nutzen. Jeder solche Aufruf muss zusätzlich Ihr persönliches Passwort im Header X-Personal-Password senden; es wird nie gespeichert. Für Ihre eigenen Headless-Läufe."
806
813
  },
807
814
  "scopes": {
808
815
  "read": "Nur Lesen",
@@ -3527,7 +3527,9 @@
3527
3527
  "createdBy": "created by {user}",
3528
3528
  "createdByYou": "you",
3529
3529
  "createdByKey": "API key {id}",
3530
- "revoke": "Revoke token"
3530
+ "revoke": "Revoke token",
3531
+ "boundToYou": "Your subscription",
3532
+ "boundToOther": "{user}'s subscription"
3531
3533
  },
3532
3534
  "add": {
3533
3535
  "heading": "Create a token",
@@ -3536,7 +3538,12 @@
3536
3538
  "labelPlaceholder": "e.g. CI pipeline",
3537
3539
  "scope": "Scope",
3538
3540
  "scopeHelp": "What this token can do: read-only, read and write, or full access (which also allows deleting).",
3539
- "create": "Create token"
3541
+ "create": "Create token",
3542
+ "identity": "Runs as",
3543
+ "identitySystem": "This workspace (system token)",
3544
+ "identitySelf": "Me (personal token)",
3545
+ "identitySystemHelp": "Runs started with this token belong to the workspace and are attributed to no person. It cannot use anyone’s personal Claude / Codex / GLM subscription, so a task pinned to one of those models is refused rather than charged to someone who is not there. Use this for CI and shared integrations.",
3546
+ "identitySelfHelp": "Runs started with this token count as yours and can use your personal Claude / Codex / GLM subscription. Every such call must also send your personal password in the X-Personal-Password header; it is never stored. Use this to drive your own headless runs."
3540
3547
  },
3541
3548
  "scopes": {
3542
3549
  "read": "Read only",
@@ -3248,7 +3248,9 @@
3248
3248
  "createdBy": "creado por {user}",
3249
3249
  "createdByYou": "ti",
3250
3250
  "createdByKey": "la clave de API {id}",
3251
- "revoke": "Revocar token"
3251
+ "revoke": "Revocar token",
3252
+ "boundToYou": "Tu suscripción",
3253
+ "boundToOther": "Suscripción de {user}"
3252
3254
  },
3253
3255
  "add": {
3254
3256
  "heading": "Crear un token",
@@ -3257,7 +3259,12 @@
3257
3259
  "labelPlaceholder": "p. ej. pipeline de CI",
3258
3260
  "scope": "Alcance",
3259
3261
  "scopeHelp": "Lo que puede hacer este token: solo lectura, lectura y escritura o acceso completo (que también permite eliminar).",
3260
- "create": "Crear token"
3262
+ "create": "Crear token",
3263
+ "identity": "Se ejecuta como",
3264
+ "identitySystem": "Este espacio de trabajo (token de sistema)",
3265
+ "identitySelf": "Yo (token personal)",
3266
+ "identitySystemHelp": "Las ejecuciones iniciadas con este token pertenecen al espacio de trabajo y no se atribuyen a ninguna persona. No puede usar la suscripción personal de Claude / Codex / GLM de nadie, así que una tarea fijada a uno de esos modelos se rechaza en lugar de cargarse a alguien ausente. Úsalo para CI e integraciones compartidas.",
3267
+ "identitySelfHelp": "Las ejecuciones iniciadas con este token se te atribuyen y pueden usar tu suscripción personal de Claude / Codex / GLM. Cada llamada debe enviar además tu contraseña personal en la cabecera X-Personal-Password; nunca se almacena. Úsalo para tus propias ejecuciones headless."
3261
3268
  },
3262
3269
  "scopes": {
3263
3270
  "read": "Solo lectura",
@@ -3248,7 +3248,9 @@
3248
3248
  "createdBy": "créé par {user}",
3249
3249
  "createdByYou": "vous",
3250
3250
  "createdByKey": "la clé d’API {id}",
3251
- "revoke": "Révoquer le jeton"
3251
+ "revoke": "Révoquer le jeton",
3252
+ "boundToYou": "Votre abonnement",
3253
+ "boundToOther": "Abonnement de {user}"
3252
3254
  },
3253
3255
  "add": {
3254
3256
  "heading": "Créer un jeton",
@@ -3257,7 +3259,12 @@
3257
3259
  "labelPlaceholder": "ex. pipeline CI",
3258
3260
  "scope": "Portée",
3259
3261
  "scopeHelp": "Ce que ce jeton peut faire : lecture seule, lecture et écriture, ou accès complet (qui autorise aussi la suppression).",
3260
- "create": "Créer le jeton"
3262
+ "create": "Créer le jeton",
3263
+ "identity": "S'exécute en tant que",
3264
+ "identitySystem": "Cet espace de travail (jeton système)",
3265
+ "identitySelf": "Moi (jeton personnel)",
3266
+ "identitySystemHelp": "Les exécutions lancées avec ce jeton appartiennent à l'espace de travail et ne sont attribuées à personne. Il ne peut utiliser l'abonnement personnel Claude / Codex / GLM de qui que ce soit : une tâche fixée sur un tel modèle est refusée plutôt que facturée à quelqu'un d'absent. À utiliser pour la CI et les intégrations partagées.",
3267
+ "identitySelfHelp": "Les exécutions lancées avec ce jeton vous sont attribuées et peuvent utiliser votre abonnement personnel Claude / Codex / GLM. Chaque appel doit aussi envoyer votre mot de passe personnel dans l'en-tête X-Personal-Password ; il n'est jamais conservé. À utiliser pour vos propres exécutions headless."
3261
3268
  },
3262
3269
  "scopes": {
3263
3270
  "read": "Lecture seule",
@@ -3390,7 +3390,9 @@
3390
3390
  "createdBy": "נוצר על ידי {user}",
3391
3391
  "createdByYou": "אתה",
3392
3392
  "createdByKey": "מפתח API {id}",
3393
- "revoke": "בטל אסימון"
3393
+ "revoke": "בטל אסימון",
3394
+ "boundToYou": "המנוי שלך",
3395
+ "boundToOther": "המנוי של {user}"
3394
3396
  },
3395
3397
  "add": {
3396
3398
  "heading": "צור אסימון",
@@ -3399,7 +3401,12 @@
3399
3401
  "labelPlaceholder": "לדוגמה, צינור CI",
3400
3402
  "scope": "היקף הרשאות",
3401
3403
  "scopeHelp": "מה האסימון הזה יכול לעשות: קריאה בלבד, קריאה וכתיבה, או גישה מלאה (שמאפשרת גם מחיקה).",
3402
- "create": "צור אסימון"
3404
+ "create": "צור אסימון",
3405
+ "identity": "פועל בשם",
3406
+ "identitySystem": "סביבת העבודה הזו (אסימון מערכת)",
3407
+ "identitySelf": "אני (אסימון אישי)",
3408
+ "identitySystemHelp": "הרצות שמתחילות עם האסימון הזה שייכות לסביבת העבודה ואינן משויכות לאף אדם. הוא אינו יכול להשתמש במנוי האישי של אף אחד ל-Claude / Codex / GLM, ולכן משימה שמוצמדת למודל כזה תידחה במקום להיזקף לחובת מי שאינו נוכח. השתמשו בו ל-CI ולאינטגרציות משותפות.",
3409
+ "identitySelfHelp": "הרצות שמתחילות עם האסימון הזה נחשבות שלך ויכולות להשתמש במנוי האישי שלך ל-Claude / Codex / GLM. כל קריאה כזו חייבת לשלוח גם את הסיסמה האישית שלך בכותרת X-Personal-Password; היא לעולם אינה נשמרת. השתמשו בו להרצות headless משלכם."
3403
3410
  },
3404
3411
  "scopes": {
3405
3412
  "read": "קריאה בלבד",
@@ -793,7 +793,9 @@
793
793
  "createdBy": "creato da {user}",
794
794
  "createdByYou": "te",
795
795
  "createdByKey": "la chiave API {id}",
796
- "revoke": "Revoca token"
796
+ "revoke": "Revoca token",
797
+ "boundToYou": "Il tuo abbonamento",
798
+ "boundToOther": "Abbonamento di {user}"
797
799
  },
798
800
  "add": {
799
801
  "heading": "Crea un token",
@@ -802,7 +804,12 @@
802
804
  "labelPlaceholder": "es. pipeline CI",
803
805
  "scope": "Ambito",
804
806
  "scopeHelp": "Cosa può fare questo token: sola lettura, lettura e scrittura o accesso completo (che consente anche l'eliminazione).",
805
- "create": "Crea token"
807
+ "create": "Crea token",
808
+ "identity": "Viene eseguito come",
809
+ "identitySystem": "Questo spazio di lavoro (token di sistema)",
810
+ "identitySelf": "Io (token personale)",
811
+ "identitySystemHelp": "Le esecuzioni avviate con questo token appartengono allo spazio di lavoro e non sono attribuite a nessuna persona. Non può usare l'abbonamento personale Claude / Codex / GLM di nessuno: un'attività fissata su uno di quei modelli viene rifiutata anziché addebitata a chi non c'è. Usalo per la CI e le integrazioni condivise.",
812
+ "identitySelfHelp": "Le esecuzioni avviate con questo token sono attribuite a te e possono usare il tuo abbonamento personale Claude / Codex / GLM. Ogni chiamata deve inviare anche la tua password personale nell'intestazione X-Personal-Password; non viene mai memorizzata. Usalo per le tue esecuzioni headless."
806
813
  },
807
814
  "scopes": {
808
815
  "read": "Sola lettura",
@@ -3390,7 +3390,9 @@
3390
3390
  "createdBy": "作成者: {user}",
3391
3391
  "createdByYou": "あなた",
3392
3392
  "createdByKey": "APIキー {id}",
3393
- "revoke": "トークンを取り消す"
3393
+ "revoke": "トークンを取り消す",
3394
+ "boundToYou": "あなたのサブスクリプション",
3395
+ "boundToOther": "{user} のサブスクリプション"
3394
3396
  },
3395
3397
  "add": {
3396
3398
  "heading": "トークンを作成",
@@ -3399,7 +3401,12 @@
3399
3401
  "labelPlaceholder": "例: CI パイプライン",
3400
3402
  "scope": "権限範囲",
3401
3403
  "scopeHelp": "このトークンでできること: 読み取り専用、読み取りと書き込み、またはフルアクセス(削除も可能)。",
3402
- "create": "トークンを作成"
3404
+ "create": "トークンを作成",
3405
+ "identity": "実行者",
3406
+ "identitySystem": "このワークスペース(システムトークン)",
3407
+ "identitySelf": "自分(個人トークン)",
3408
+ "identitySystemHelp": "このトークンで開始した実行はワークスペースに属し、個人には紐づきません。誰の個人 Claude / Codex / GLM サブスクリプションも利用できないため、それらのモデルを指定したタスクは、不在の相手に課金される代わりに拒否されます。CI や共有連携にはこちらを使ってください。",
3409
+ "identitySelfHelp": "このトークンで開始した実行はあなたのものとして扱われ、あなたの個人 Claude / Codex / GLM サブスクリプションを利用できます。その際は毎回のリクエストで X-Personal-Password ヘッダーに個人パスワードを送る必要があります。パスワードは保存されません。自分のヘッドレス実行にはこちらを使ってください。"
3403
3410
  },
3404
3411
  "scopes": {
3405
3412
  "read": "読み取り専用",
@@ -3248,7 +3248,9 @@
3248
3248
  "createdBy": "utworzone przez {user}",
3249
3249
  "createdByYou": "Ciebie",
3250
3250
  "createdByKey": "klucz API {id}",
3251
- "revoke": "Unieważnij token"
3251
+ "revoke": "Unieważnij token",
3252
+ "boundToYou": "Twoja subskrypcja",
3253
+ "boundToOther": "Subskrypcja użytkownika {user}"
3252
3254
  },
3253
3255
  "add": {
3254
3256
  "heading": "Utwórz token",
@@ -3257,7 +3259,12 @@
3257
3259
  "labelPlaceholder": "np. potok CI",
3258
3260
  "scope": "Zakres",
3259
3261
  "scopeHelp": "Co może ten token: tylko odczyt, odczyt i zapis lub pełny dostęp (który pozwala także na usuwanie).",
3260
- "create": "Utwórz token"
3262
+ "create": "Utwórz token",
3263
+ "identity": "Działa jako",
3264
+ "identitySystem": "Ten obszar roboczy (token systemowy)",
3265
+ "identitySelf": "Ja (token osobisty)",
3266
+ "identitySystemHelp": "Uruchomienia rozpoczęte tym tokenem należą do obszaru roboczego i nie są przypisywane do żadnej osoby. Token nie może korzystać z niczyjej osobistej subskrypcji Claude / Codex / GLM, więc zadanie przypięte do takiego modelu zostanie odrzucone, zamiast obciążyć kogoś nieobecnego. Użyj go do CI i wspólnych integracji.",
3267
+ "identitySelfHelp": "Uruchomienia rozpoczęte tym tokenem są przypisywane Tobie i mogą korzystać z Twojej osobistej subskrypcji Claude / Codex / GLM. Każde takie wywołanie musi dodatkowo przesłać Twoje hasło osobiste w nagłówku X-Personal-Password; nie jest ono nigdzie zapisywane. Użyj go do własnych uruchomień headless."
3261
3268
  },
3262
3269
  "scopes": {
3263
3270
  "read": "Tylko odczyt",
@@ -3390,7 +3390,9 @@
3390
3390
  "createdBy": "oluşturan: {user}",
3391
3391
  "createdByYou": "siz",
3392
3392
  "createdByKey": "{id} API anahtarı",
3393
- "revoke": "Belirteci iptal et"
3393
+ "revoke": "Belirteci iptal et",
3394
+ "boundToYou": "Aboneliğiniz",
3395
+ "boundToOther": "{user} kullanıcısının aboneliği"
3394
3396
  },
3395
3397
  "add": {
3396
3398
  "heading": "Belirteç oluştur",
@@ -3399,7 +3401,12 @@
3399
3401
  "labelPlaceholder": "örn. CI hattı",
3400
3402
  "scope": "Kapsam",
3401
3403
  "scopeHelp": "Bu belirtecin yapabilecekleri: yalnızca okuma, okuma ve yazma ya da tam erişim (silmeye de izin verir).",
3402
- "create": "Belirteç oluştur"
3404
+ "create": "Belirteç oluştur",
3405
+ "identity": "Şu kimlikle çalışır",
3406
+ "identitySystem": "Bu çalışma alanı (sistem belirteci)",
3407
+ "identitySelf": "Ben (kişisel belirteç)",
3408
+ "identitySystemHelp": "Bu belirteçle başlatılan çalıştırmalar çalışma alanına aittir ve hiçbir kişiye atfedilmez. Kimsenin kişisel Claude / Codex / GLM aboneliğini kullanamaz; bu nedenle böyle bir modele sabitlenmiş görev, orada olmayan birine fatura edilmek yerine reddedilir. CI ve paylaşılan entegrasyonlar için bunu kullanın.",
3409
+ "identitySelfHelp": "Bu belirteçle başlatılan çalıştırmalar size ait sayılır ve kişisel Claude / Codex / GLM aboneliğinizi kullanabilir. Bu tür her çağrının ayrıca kişisel parolanızı X-Personal-Password başlığında göndermesi gerekir; parola hiçbir zaman saklanmaz. Kendi headless çalıştırmalarınız için bunu kullanın."
3403
3410
  },
3404
3411
  "scopes": {
3405
3412
  "read": "Yalnızca okuma",
@@ -3248,7 +3248,9 @@
3248
3248
  "createdBy": "створено {user}",
3249
3249
  "createdByYou": "вами",
3250
3250
  "createdByKey": "ключ API {id}",
3251
- "revoke": "Відкликати токен"
3251
+ "revoke": "Відкликати токен",
3252
+ "boundToYou": "Ваша підписка",
3253
+ "boundToOther": "Підписка {user}"
3252
3254
  },
3253
3255
  "add": {
3254
3256
  "heading": "Створити токен",
@@ -3257,7 +3259,12 @@
3257
3259
  "labelPlaceholder": "напр. конвеєр CI",
3258
3260
  "scope": "Обсяг доступу",
3259
3261
  "scopeHelp": "Що може цей токен: лише читання, читання та запис або повний доступ (який також дозволяє видалення).",
3260
- "create": "Створити токен"
3262
+ "create": "Створити токен",
3263
+ "identity": "Виконується як",
3264
+ "identitySystem": "Цей робочий простір (системний токен)",
3265
+ "identitySelf": "Я (особистий токен)",
3266
+ "identitySystemHelp": "Запуски, розпочаті цим токеном, належать робочому простору й не приписуються жодній особі. Він не може використовувати чиюсь особисту підписку Claude / Codex / GLM, тож завдання, закріплене за такою моделлю, буде відхилено, а не оплачено коштом відсутньої людини. Використовуйте його для CI та спільних інтеграцій.",
3267
+ "identitySelfHelp": "Запуски, розпочаті цим токеном, вважаються вашими й можуть використовувати вашу особисту підписку Claude / Codex / GLM. Кожен такий виклик має також надсилати ваш особистий пароль у заголовку X-Personal-Password; він ніколи не зберігається. Використовуйте його для власних headless-запусків."
3261
3268
  },
3262
3269
  "scopes": {
3263
3270
  "read": "Лише читання",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cat-factory/app",
3
- "version": "0.262.0",
3
+ "version": "0.263.0",
4
4
  "description": "Reusable Nuxt layer for the Agent Architecture Board SPA (components, stores, composables, pages). Consume it from a thin deployment app via `extends: ['@cat-factory/app']` and point it at your backend with NUXT_PUBLIC_API_BASE. See deploy/frontend for an example.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -40,7 +40,7 @@
40
40
  "valibot": "^1.4.2",
41
41
  "vue": "3.5.41",
42
42
  "wretch": "^3.0.9",
43
- "@cat-factory/contracts": "0.297.0"
43
+ "@cat-factory/contracts": "0.298.0"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@toad-contracts/testing": "0.3.2",