@sumdaelive/cli 0.1.3 → 0.1.4
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.
- package/dist/main.js +1176 -417
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -44,7 +44,7 @@ import { useEffect as useEffect9 } from "react";
|
|
|
44
44
|
// src/app.tsx
|
|
45
45
|
import { Box as Box16, Text as Text19, useApp as useApp3, useInput as useInput5 } from "ink";
|
|
46
46
|
import open from "open";
|
|
47
|
-
import { useEffect as useEffect7, useState as useState9 } from "react";
|
|
47
|
+
import { useEffect as useEffect7, useRef as useRef4, useState as useState9 } from "react";
|
|
48
48
|
|
|
49
49
|
// src/config.ts
|
|
50
50
|
import { mkdirSync, readFileSync, renameSync, writeFileSync } from "fs";
|
|
@@ -73,6 +73,718 @@ function saveConfig(cfg) {
|
|
|
73
73
|
// src/credentials.ts
|
|
74
74
|
import { mkdirSync as mkdirSync2, readFileSync as readFileSync2, renameSync as renameSync2, rmSync, writeFileSync as writeFileSync2 } from "fs";
|
|
75
75
|
import { join as join2 } from "path";
|
|
76
|
+
|
|
77
|
+
// src/i18n-catalog.ts
|
|
78
|
+
var CATALOG = {
|
|
79
|
+
fr: {
|
|
80
|
+
"agentFeed.agent.subagent": "sous-agent {n}",
|
|
81
|
+
"agentFeed.agent.sumdae": "agent sumdae",
|
|
82
|
+
"agentFeed.diff.moreLines": "\u2026 ({n} lignes de plus)",
|
|
83
|
+
"agentFeed.lagged": "\u2026 (flux rattrap\xE9)",
|
|
84
|
+
"agentFeed.result.failed": "\xE9chec",
|
|
85
|
+
"agentFeed.result.ok": "ok",
|
|
86
|
+
"agentFeed.shell": "shell",
|
|
87
|
+
"api.authRequired": "session expir\xE9e ou absente \u2014 lancez `sumdae login`",
|
|
88
|
+
"api.permissionDenied": "Vous n'avez pas la permission d'effectuer cette action.",
|
|
89
|
+
"api.quotaInsufficient": "quota de build insuffisant : {remaining} restant(s), {needed} requis",
|
|
90
|
+
"api.quotaInvalidResponse": "r\xE9ponse quota invalide \u2014 v\xE9rification impossible, refus par prudence",
|
|
91
|
+
"api.tokenExchangeFailed": "\xE9chec de l'\xE9change de token",
|
|
92
|
+
"banner.tagline": "la plateforme sumdae, depuis le terminal",
|
|
93
|
+
"buildCmd.buildLaunched": "build {buildId} lanc\xE9 \u2014 quota consomm\xE9",
|
|
94
|
+
"buildCmd.cancelRequested": "annulation demand\xE9e \u2014 suivi jusqu\u2019\xE0 l\u2019arr\xEAt complet :",
|
|
95
|
+
"buildCmd.commandSent": "commande \xAB {action} \xBB envoy\xE9e \xE0 {agent}",
|
|
96
|
+
"buildCmd.invalidAction": "action invalide \u2014 'kill' ou 'message'",
|
|
97
|
+
"buildCmd.noActiveOrgForCancel": "aucune organisation active",
|
|
98
|
+
"buildCmd.simEmpty": 't\xE2che vide \u2014 donne une instruction au master, ex. : sumdae simulate "cr\xE9e /workspace/hello.txt et liste le dossier"',
|
|
99
|
+
"buildCmd.simLaunched": "simulation {buildId} lanc\xE9e \u2014 quota consomm\xE9 \xB7 pod lou\xE9, agents au travail",
|
|
100
|
+
"buildSummary.heading": "r\xE9sum\xE9 du job",
|
|
101
|
+
"buildSummary.rewatch": "Revoir le flux complet",
|
|
102
|
+
"buildSummary.rewatch.hint": "rejouer les events",
|
|
103
|
+
"buildSummary.watchLive": "Voir le job en cours",
|
|
104
|
+
"buildWatch.connectionLost": "connexion au build perdue (30 tentatives) \u2014 relancez `sumdae watch`",
|
|
105
|
+
"buildWatch.refused": "watch refus\xE9 (HTTP {status})",
|
|
106
|
+
"cli.agent.description": "piloter les agents d\u2019un build",
|
|
107
|
+
"cli.agent.kill.description": "arr\xEAter un agent (d\xE9faut : master)",
|
|
108
|
+
"cli.agent.msg.description": "envoyer un message \xE0 un agent en cours",
|
|
109
|
+
"cli.agent.opt.agent": "master | subagent-N | all",
|
|
110
|
+
"cli.build.description": "lancer un build Docker (consomme 1 quota) et suivre en live",
|
|
111
|
+
"cli.build.opt.pipeline": "artifact pipeline \xE0 int\xE9grer",
|
|
112
|
+
"cli.cancel.description": "annuler un build (environnement lib\xE9r\xE9, quota rembours\xE9 si rien commenc\xE9)",
|
|
113
|
+
"cli.login.description": "se connecter \xE0 sumdae (OAuth + PKCE)",
|
|
114
|
+
"cli.login.opt.noBrowser": "afficher l'URL au lieu d'ouvrir le navigateur",
|
|
115
|
+
"cli.login.opt.withKey": "coller une cl\xE9 API lab_\u2026 (headless)",
|
|
116
|
+
"cli.logout.description": "se d\xE9connecter",
|
|
117
|
+
"cli.org.description": "g\xE9rer les organisations",
|
|
118
|
+
"cli.org.list.description": "lister vos organisations",
|
|
119
|
+
"cli.org.switch.description": "changer d'organisation active",
|
|
120
|
+
"cli.push.description": "uploader des poids ou un pipeline vers l'organisation active",
|
|
121
|
+
"cli.push.opt.kind": "weights | pipeline (d\xE9duit de l\u2019extension sinon)",
|
|
122
|
+
"cli.quota.description": "builds restants de l'organisation active",
|
|
123
|
+
"cli.root.description": "CLI de la plateforme sumdae",
|
|
124
|
+
"cli.simulate.description": "lancer un build SIMULATION \u2014 pas besoin de mod\xE8le/pipeline (consomme 1 quota)",
|
|
125
|
+
"cli.uninstall.description": "supprimer proprement sumdae de cette machine (tous canaux)",
|
|
126
|
+
"cli.uninstall.opt.yes": "ne pas demander de confirmation (headless)",
|
|
127
|
+
"cli.watch.description": "suivre un build en cours (WS temps r\xE9el)",
|
|
128
|
+
"cli.whoami.description": "profil + organisation active",
|
|
129
|
+
"common.activeOrgLabel": "organisation active :",
|
|
130
|
+
"common.activeOrgSet": "organisation active : {name}",
|
|
131
|
+
"common.back": "Retourner en arri\xE8re",
|
|
132
|
+
"common.backToHome": "Retourner \xE0 l'accueil",
|
|
133
|
+
"common.connectedAs": "connect\xE9 : {email}",
|
|
134
|
+
"common.creatingJob": "cr\xE9ation du job\u2026",
|
|
135
|
+
"common.jobImpossible": "job impossible",
|
|
136
|
+
"common.loginFailed": "connexion \xE9chou\xE9e",
|
|
137
|
+
"common.noActiveOrgRunSwitch": "aucune organisation active \u2014 lancez `sumdae org switch`",
|
|
138
|
+
"common.noOrgCreateOnLab": "aucune organisation \u2014 cr\xE9ez-en une sur lab.sumdae.fr",
|
|
139
|
+
"common.orEscape": "ou \xC9chap",
|
|
140
|
+
"common.quit": "Quitter",
|
|
141
|
+
"common.signingOut": "d\xE9connexion\u2026",
|
|
142
|
+
"common.terminalCurrent": "(actuel : {cols}\xD7{rows})",
|
|
143
|
+
"common.terminalEnlarge": "Agrandissez \xE0 {cols}\xD7{rows} minimum",
|
|
144
|
+
"common.terminalTooSmall": "Terminal trop petit",
|
|
145
|
+
"common.truncated": "\u2026 (tronqu\xE9)",
|
|
146
|
+
"common.waitingBrowserLogin": "en attente de la connexion dans le navigateur\u2026",
|
|
147
|
+
"credentials.keychainFallback": "\u26A0 trousseau syst\xE8me indisponible \u2014 credentials stock\xE9s dans {path} (chmod 600)",
|
|
148
|
+
"credentials.keyringUnavailable": "\u26A0 trousseau syst\xE8me indisponible \u2014 credentials stock\xE9s dans {filePath} (chmod 600)",
|
|
149
|
+
"directUpload.err.refused": "upload refus\xE9 par l'environnement (HTTP {status})",
|
|
150
|
+
"help.build": "lancer un build + suivi live",
|
|
151
|
+
"help.cancel": "annuler un build proprement",
|
|
152
|
+
"help.heading": "COMMANDES \xB7 v{version}",
|
|
153
|
+
"help.login": "se connecter (OAuth + PKCE)",
|
|
154
|
+
"help.logout": "se d\xE9connecter",
|
|
155
|
+
"help.push": "uploader poids/pipeline (R2)",
|
|
156
|
+
"help.quota": "builds restants de l'org active",
|
|
157
|
+
"help.watch": "suivre un build en cours",
|
|
158
|
+
"home.actions": "actions",
|
|
159
|
+
"home.job.kind.build": "build",
|
|
160
|
+
"home.job.kind.sim": "sim",
|
|
161
|
+
"home.loadingHistory": "chargement de l\u2019historique\u2026",
|
|
162
|
+
"home.menu.job": "Lancer un job",
|
|
163
|
+
"home.menu.job.hint": "int\xE9grer un mod\xE8le (Hugging Face ou fichier local)",
|
|
164
|
+
"home.menu.lang.hint": "\u2190/\u2192 pour changer",
|
|
165
|
+
"home.menu.logout": "Se d\xE9connecter",
|
|
166
|
+
"home.menu.orgs": "Changer d'organisation",
|
|
167
|
+
"home.menu.quota": "Quota de build",
|
|
168
|
+
"home.menu.quota.hint": "builds restants",
|
|
169
|
+
"home.menu.refresh": "Rafra\xEEchir l\u2019historique",
|
|
170
|
+
"home.menu.simulate": "Lancer une simulation",
|
|
171
|
+
"home.menu.simulate.hint": "t\xE2che libre \u2014 dry-run du pipeline complet",
|
|
172
|
+
"home.menu.uninstall": "D\xE9sinstaller sumdae",
|
|
173
|
+
"home.menu.uninstall.hint": "supprimer la CLI de cette machine",
|
|
174
|
+
"home.menu.whoami": "Qui suis-je",
|
|
175
|
+
"home.menu.whoami.hint": "profil complet",
|
|
176
|
+
"home.noActiveOrg": "\u2014 aucune organisation",
|
|
177
|
+
"home.noJobsYet": "aucun job pour le moment \u2014 lancez une simulation pour commencer",
|
|
178
|
+
"home.recentJobs": "derniers jobs",
|
|
179
|
+
"home.sessionLabel": "session : {session}",
|
|
180
|
+
"home.static.orgLine": "organisation : {name}",
|
|
181
|
+
"home.static.orgNone": "organisation : \u2014 (sumdae org switch)",
|
|
182
|
+
"home.static.sessionApiKey": "session : cl\xE9 API",
|
|
183
|
+
"home.static.sessionOauth": "session : oauth",
|
|
184
|
+
"job.fetching": "r\xE9cup\xE9ration du job\u2026",
|
|
185
|
+
"job.file.err.empty.title": "fichier vide",
|
|
186
|
+
"job.file.err.notFile.detail": "{path} est un dossier \u2014 fournis un fichier de poids ou une archive.",
|
|
187
|
+
"job.file.err.notFile.title": "pas un fichier",
|
|
188
|
+
"job.file.err.notFound.title": "fichier introuvable",
|
|
189
|
+
"job.file.placeholder": "ex. : ~/models/mistral-7b.safetensors ou ./weights.tar.gz",
|
|
190
|
+
"job.file.title": "Fichier de poids / archive locale",
|
|
191
|
+
"job.fileConfirm.changeFile": "Changer de fichier",
|
|
192
|
+
"job.fileConfirm.fileLabel": "fichier : ",
|
|
193
|
+
"job.fileConfirm.gotItLaunch": "J'ai compris \u2014 lancer le job",
|
|
194
|
+
"job.fileConfirm.title": "envoi direct vers l'environnement",
|
|
195
|
+
"job.fileConfirm.warnDirect": "\u26A0 le fichier est stream\xE9 DIRECTEMENT de cette machine vers l'environnement (il ne transite par aucun serveur interm\xE9diaire).",
|
|
196
|
+
"job.fileConfirm.warnKeepAlive": "garde ta machine allum\xE9e et ta connexion stable pendant tout l'envoi : si la connexion est interrompue, le job est coup\xE9 automatiquement.",
|
|
197
|
+
"job.hf.checking": "v\xE9rification de l'acc\xE8s Hugging Face\u2026",
|
|
198
|
+
"job.hf.err.checkFailed.title": "v\xE9rification Hugging Face \xE9chou\xE9e",
|
|
199
|
+
"job.hf.err.gated.detail": "Le repo est gated : accepte ses conditions sur huggingface.co avec le compte du token, ou v\xE9rifie que le token a bien l'acc\xE8s en lecture.",
|
|
200
|
+
"job.hf.err.gated.title": "acc\xE8s refus\xE9 \xE0 ce mod\xE8le",
|
|
201
|
+
"job.hf.err.invalidToken.detail": "Le token configur\xE9 pour ton organisation est invalide ou r\xE9voqu\xE9 \u2014 mets-le \xE0 jour dans lab.sumdae.fr \u2192 \xAB Param\xE8tres org. \xBB.",
|
|
202
|
+
"job.hf.err.invalidToken.title": "token Hugging Face invalide",
|
|
203
|
+
"job.hf.err.noToken.detail": "Ton organisation n'a pas de token Hugging Face configur\xE9.\nAjoute un token READ : lab.sumdae.fr \u2192 menu du compte (en bas de la sidebar) \u2192 \xAB Param\xE8tres org. \xBB \u2192 Hugging Face token.\nCr\xE9e le token sur huggingface.co \u2192 Settings \u2192 Access Tokens (Read).",
|
|
204
|
+
"job.hf.err.noToken.title": "token Hugging Face manquant",
|
|
205
|
+
"job.hf.err.notFound.detail": "Repo ou r\xE9vision inexistants sur Hugging Face \u2014 ou repo priv\xE9 invisible pour ce token. V\xE9rifie le lien.",
|
|
206
|
+
"job.hf.err.notFound.title": "mod\xE8le introuvable",
|
|
207
|
+
"job.hf.invalidRef.detail": "Formats accept\xE9s : owner/repo, owner/repo@revision, ou une URL huggingface.co compl\xE8te.",
|
|
208
|
+
"job.hf.invalidRef.title": "r\xE9f\xE9rence invalide",
|
|
209
|
+
"job.hf.noToken": "aucun token HF configur\xE9 \u2014 ajoutez-en un dans Param\xE8tres org. sur lab.sumdae.fr",
|
|
210
|
+
"job.hf.placeholder": "ex. : mistralai/Mistral-7B-v0.1, owner/repo@rev, ou URL huggingface.co",
|
|
211
|
+
"job.hf.title": "Mod\xE8le Hugging Face",
|
|
212
|
+
"job.hf.tokenLabel": "token HF : ",
|
|
213
|
+
"job.hf.tokenMasked": "({masked})",
|
|
214
|
+
"job.hfConfirm.editLink": "Modifier le lien",
|
|
215
|
+
"job.hfConfirm.explain": "le mod\xE8le sera t\xE9l\xE9charg\xE9 sur l'environnement, int\xE9gr\xE9 dans la template, test\xE9, puis l'image Docker sera publi\xE9e. 1 build de quota sera consomm\xE9.",
|
|
216
|
+
"job.hfConfirm.gated": "\xB7 repo gated (acc\xE8s accord\xE9)",
|
|
217
|
+
"job.hfConfirm.launch": "Lancer le job",
|
|
218
|
+
"job.hfConfirm.repo": "repo : ",
|
|
219
|
+
"job.hfConfirm.sizeEstimate": "taille estim\xE9e : ",
|
|
220
|
+
"job.hfConfirm.sizeUnknown": "inconnue",
|
|
221
|
+
"job.hfConfirm.title": "mod\xE8le v\xE9rifi\xE9 \u2014 acc\xE8s OK",
|
|
222
|
+
"job.noUploadToken": "r\xE9ponse serveur sans upload_token",
|
|
223
|
+
"job.notFound": "job introuvable",
|
|
224
|
+
"job.source.file": "Fichier local",
|
|
225
|
+
"job.source.file.hint": "stream\xE9 depuis cette machine vers l\u2019environnement",
|
|
226
|
+
"job.source.hf": "Lien Hugging Face",
|
|
227
|
+
"job.source.hf.hint": "t\xE9l\xE9charg\xE9 directement sur l\u2019environnement (token org requis)",
|
|
228
|
+
"job.source.question": "d'o\xF9 viennent les poids du mod\xE8le \xE0 int\xE9grer ?",
|
|
229
|
+
"job.source.title": "lancer un job",
|
|
230
|
+
"jobLine.relative.daysAgo": "il y a {n} j",
|
|
231
|
+
"jobLine.relative.hoursAgo": "il y a {n} h",
|
|
232
|
+
"jobLine.relative.minutesAgo": "il y a {n} min",
|
|
233
|
+
"jobLine.relative.secondsAgo": "il y a {n} s",
|
|
234
|
+
"jobSummary.costAgentValue": "{cost} \xB7 {calls} appel(s)",
|
|
235
|
+
"jobSummary.row.costAgent": "co\xFBt agent",
|
|
236
|
+
"jobSummary.row.costEnv": "co\xFBt environnement",
|
|
237
|
+
"jobSummary.row.costTotal": "co\xFBt total",
|
|
238
|
+
"jobSummary.row.duration": "dur\xE9e",
|
|
239
|
+
"jobSummary.row.environment": "environnement",
|
|
240
|
+
"jobSummary.row.error": "erreur",
|
|
241
|
+
"jobSummary.row.status": "statut",
|
|
242
|
+
"jobSummary.row.task": "t\xE2che",
|
|
243
|
+
"jobSummary.row.type": "type",
|
|
244
|
+
"jobSummary.row.weights": "poids",
|
|
245
|
+
"jobSummary.type.build": "build",
|
|
246
|
+
"jobSummary.type.simulation": "simulation",
|
|
247
|
+
"keycaps.back": "retour",
|
|
248
|
+
"keycaps.cancel": "annuler",
|
|
249
|
+
"keycaps.checkAccess": "v\xE9rifier l\u2019acc\xE8s",
|
|
250
|
+
"keycaps.escBack": "retour",
|
|
251
|
+
"keycaps.navigate": "naviguer",
|
|
252
|
+
"keycaps.newline": "nouvelle ligne",
|
|
253
|
+
"keycaps.send": "envoyer",
|
|
254
|
+
"keycaps.switchZone": "basculer zone",
|
|
255
|
+
"keycaps.validate": "valider",
|
|
256
|
+
"landing.howConnect": "comment voulez-vous vous connecter ?",
|
|
257
|
+
"landing.menu.browser": "Se connecter via le navigateur",
|
|
258
|
+
"landing.menu.browser.hint": "OAuth + PKCE",
|
|
259
|
+
"landing.menu.key": "Coller une cl\xE9 API",
|
|
260
|
+
"landing.menu.key.hint": "lab_\u2026 \xB7 headless",
|
|
261
|
+
"landing.menu.later": "Plus tard",
|
|
262
|
+
"landing.menu.later.hint": "`sumdae login` quand vous voulez",
|
|
263
|
+
"login.browser.copyUrl": "si rien ne s'ouvre, copiez cette URL :",
|
|
264
|
+
"login.browser.openUrl": "ouvrez cette URL pour vous connecter :",
|
|
265
|
+
"login.connectedBody": "Vous pouvez fermer cet onglet et revenir au terminal.",
|
|
266
|
+
"login.connectedTitle": "\u2713 Connect\xE9",
|
|
267
|
+
"login.err.invalidState": "state invalide (possible CSRF) \u2014 flow abandonn\xE9",
|
|
268
|
+
"login.err.missingCode": "code manquant dans le callback",
|
|
269
|
+
"login.err.noBrowserResponse": "aucune r\xE9ponse du navigateur apr\xE8s {min} min",
|
|
270
|
+
"login.err.serverRefused": "refus\xE9 par le serveur d'identit\xE9 : {error}",
|
|
271
|
+
"login.failedTitle": "\u2717 \xC9chec de la connexion",
|
|
272
|
+
"login.invalidKey": "cl\xE9 API invalide",
|
|
273
|
+
"login.key.placeholder": "lab_\u2026",
|
|
274
|
+
"login.key.prompt": "cl\xE9 API (lab_\u2026) : ",
|
|
275
|
+
"login.key.title": "Cl\xE9 API",
|
|
276
|
+
"login.noKeyProvided": "aucune cl\xE9 fournie",
|
|
277
|
+
"login.noOrgCreateThenSwitch": "choisissez une organisation avec `sumdae org switch` (TTY)",
|
|
278
|
+
"login.nonInteractiveTty": "terminal non interactif \u2014 utilisez `sumdae login --no-browser` dans un TTY, ou `--with-key`",
|
|
279
|
+
"login.validatingKey": "validation de la cl\xE9\u2026",
|
|
280
|
+
"logout.done": "d\xE9connect\xE9",
|
|
281
|
+
"memory.duplicate": "LE\xC7ON D\xC9J\xC0 CONNUE",
|
|
282
|
+
"memory.query": "M\xC9MOIRE",
|
|
283
|
+
"memory.resultHit": "LE\xC7ON TROUV\xC9E",
|
|
284
|
+
"memory.resultMiss": "RIEN EN M\xC9MOIRE",
|
|
285
|
+
"memory.saved": "LE\xC7ON ENREGISTR\xC9E",
|
|
286
|
+
"memory.scorePrefix": "score {score} ",
|
|
287
|
+
"noOrg.continue": "Continuer sans organisation",
|
|
288
|
+
"noOrg.createThenReturn": "cr\xE9ez-en une sur lab.sumdae.fr puis revenez ici.",
|
|
289
|
+
"noOrg.none": "aucune organisation associ\xE9e \xE0 ce compte.",
|
|
290
|
+
"noOrg.retry": "R\xE9essayer",
|
|
291
|
+
"noOrg.retry.hint": "recharger vos organisations",
|
|
292
|
+
"orgs.fetchFailed": "impossible de r\xE9cup\xE9rer les organisations",
|
|
293
|
+
"orgs.loading": "chargement des organisations\u2026",
|
|
294
|
+
"orgs.nonInteractiveTty": "terminal non interactif \u2014 impossible de choisir une organisation",
|
|
295
|
+
"orgs.role.member": "member",
|
|
296
|
+
"progress.build": "BUILD",
|
|
297
|
+
"progress.download": "T\xC9L\xC9CHARGEMENT",
|
|
298
|
+
"progress.elapsed": " \xB7 {duration} \xE9coul\xE9",
|
|
299
|
+
"progress.generic": "\xC9TAPE",
|
|
300
|
+
"progress.inProgress": "en cours",
|
|
301
|
+
"progress.install": "INSTALLATION",
|
|
302
|
+
"progress.push": "PUSH IMAGE",
|
|
303
|
+
"progress.transferred": " transf\xE9r\xE9s",
|
|
304
|
+
"progress.waitingNetwork": " \xB7 en attente du r\xE9seau\u2026 {duration}",
|
|
305
|
+
"promptBox.hint": "entr\xE9e = envoyer \xB7 \\ + entr\xE9e = nouvelle ligne \xB7 esc = retour",
|
|
306
|
+
"push.failed.title": "push \xE9chou\xE9",
|
|
307
|
+
"push.hashing": "sha256 de {filePath}\u2026",
|
|
308
|
+
"push.inferKindFailed": "impossible de d\xE9duire le type \u2014 pr\xE9cisez --kind weights ou --kind pipeline",
|
|
309
|
+
"push.uploaded": "artifact upload\xE9",
|
|
310
|
+
"quota.exhausted": "quota \xE9puis\xE9 \u2014 demandez \xE0 l'admin d'augmenter build_quota",
|
|
311
|
+
"quota.loading": "quota de build\u2026",
|
|
312
|
+
"quota.row.note": "note",
|
|
313
|
+
"quota.row.remaining": "builds restants",
|
|
314
|
+
"quota.unreachable": "quota de build inaccessible",
|
|
315
|
+
"selectList.hint": "\u2191\u2193 naviguer \xB7 entr\xE9e valider",
|
|
316
|
+
"simulate.creating": "cr\xE9ation de la simulation\u2026",
|
|
317
|
+
"simulate.impossible": "simulation impossible",
|
|
318
|
+
"simulate.placeholder": "ex. : cr\xE9e /workspace/hello.txt avec \xAB bonjour \xBB et liste le dossier",
|
|
319
|
+
"simulate.title": "T\xE2che pour le master \xB7 mode SIMULATION",
|
|
320
|
+
"uninstall.cancel": "Annuler",
|
|
321
|
+
"uninstall.cancel.hint": "ne rien supprimer",
|
|
322
|
+
"uninstall.channel.binary": "binaire",
|
|
323
|
+
"uninstall.channel.npm": "npm (global)",
|
|
324
|
+
"uninstall.channel.selfhosted": "auto-h\xE9berg\xE9",
|
|
325
|
+
"uninstall.cli.cancelled": "annul\xE9.",
|
|
326
|
+
"uninstall.cli.channel": " canal : {channel}",
|
|
327
|
+
"uninstall.cli.cleaned": "config et identifiants nettoy\xE9s ; l\u2019install sera effac\xE9e \xE0 la fermeture.",
|
|
328
|
+
"uninstall.cli.config": " config : {configDir}",
|
|
329
|
+
"uninstall.cli.credentials": " credentials : trousseau + fichier",
|
|
330
|
+
"uninstall.cli.heading": "D\xE9sinstallation de sumdae :",
|
|
331
|
+
"uninstall.cli.installGlobal": "npm uninstall -g (global)",
|
|
332
|
+
"uninstall.cli.installLine": " install : {install}",
|
|
333
|
+
"uninstall.cli.installManual": " install : manuel \u2192 {hint}",
|
|
334
|
+
"uninstall.cli.launcher": " launcher : {launcher}",
|
|
335
|
+
"uninstall.cli.manualFallback": "\xE0 faire manuellement",
|
|
336
|
+
"uninstall.cli.stepFailed": "\xE9chec",
|
|
337
|
+
"uninstall.close": "Fermer",
|
|
338
|
+
"uninstall.config.now": "{configDir} (maintenant)",
|
|
339
|
+
"uninstall.confirm.title": "D\xE9sinstaller sumdae",
|
|
340
|
+
"uninstall.confirm.warning": "ceci supprimera d\xE9finitivement la CLI et toutes ses donn\xE9es de cette machine :",
|
|
341
|
+
"uninstall.confirmDelete": "Oui, tout supprimer",
|
|
342
|
+
"uninstall.credentials.keychainFileNow": "trousseau + fichier (maintenant)",
|
|
343
|
+
"uninstall.install.atClose": "{root} (\xE0 la fermeture)",
|
|
344
|
+
"uninstall.install.manual": "\u26A0 manuel \u2192 {hint}",
|
|
345
|
+
"uninstall.install.npmAtClose": "npm uninstall -g @sumdaelive/cli (\xE0 la fermeture)",
|
|
346
|
+
"uninstall.report.done": "config et identifiants supprim\xE9s. sumdae sera effac\xE9 \xE0 la fermeture de ce terminal.",
|
|
347
|
+
"uninstall.report.someFailed": "certaines suppressions ont \xE9chou\xE9 \u2014 voir ci-dessus.",
|
|
348
|
+
"uninstall.report.title": "D\xE9sinstallation",
|
|
349
|
+
"uninstall.row.channel": "canal",
|
|
350
|
+
"uninstall.row.config": "config",
|
|
351
|
+
"uninstall.row.credentials": "credentials",
|
|
352
|
+
"uninstall.row.install": "install",
|
|
353
|
+
"uninstall.scheduleFailed": "planification \xE9chou\xE9e ({err}) \u2014 manuel : {manual}",
|
|
354
|
+
"uninstall.working": "suppression en cours\u2026",
|
|
355
|
+
"update.doneRestarting": "\u2713 install\xE9 \u2014 red\xE9marrage\u2026",
|
|
356
|
+
"update.downloading": "t\xE9l\xE9chargement\u2026",
|
|
357
|
+
"update.err.extractFailed": "extraction tar \xE9chou\xE9e",
|
|
358
|
+
"update.err.invalidSignature": "signature invalide \u2014 mise \xE0 jour refus\xE9e",
|
|
359
|
+
"update.err.npmFailed": "npm install a \xE9chou\xE9",
|
|
360
|
+
"update.err.sha256Mismatch": "sha256 du tarball ne correspond pas",
|
|
361
|
+
"update.failed": "\xE9chec de la mise \xE0 jour",
|
|
362
|
+
"update.forcedFailed": "Cette version ({current}) n'est plus support\xE9e et la mise \xE0 jour a \xE9chou\xE9 : {err}\nR\xE9essayez, ou r\xE9installez : https://lab.sumdae.fr/cli",
|
|
363
|
+
"update.installing": "installation\u2026",
|
|
364
|
+
"update.screen.title": "Mise \xE0 jour",
|
|
365
|
+
"update.verifyingSignature": "v\xE9rification de la signature\u2026",
|
|
366
|
+
"upload.bytesSent": "({bytes} envoy\xE9s)",
|
|
367
|
+
"upload.cancelledBeforeStart": "annul\xE9 avant le d\xE9but de l\u2019upload \u2014 le job sera coup\xE9 automatiquement c\xF4t\xE9 serveur (quota rembours\xE9).",
|
|
368
|
+
"upload.connInterrupted": "connexion interrompue pendant l'upload \u2014 le job va \xEAtre coup\xE9 c\xF4t\xE9 serveur ({detail})",
|
|
369
|
+
"upload.envNotReady": "l'environnement n'a pas \xE9t\xE9 pr\xEAt \xE0 temps pour recevoir le fichier",
|
|
370
|
+
"upload.envRate": "d\xE9bit environnement : ",
|
|
371
|
+
"upload.err.cancelled": "upload annul\xE9",
|
|
372
|
+
"upload.err.missingEtag": "ETag manquant dans la r\xE9ponse R2",
|
|
373
|
+
"upload.err.missingPresigned": "URL pr\xE9sign\xE9e manquante pour la part {n}",
|
|
374
|
+
"upload.err.partFailed": "part {n}/{total} en \xE9chec apr\xE8s {tries} tentatives : {msg}",
|
|
375
|
+
"upload.etaLabel": "temps restant estim\xE9 : ",
|
|
376
|
+
"upload.interrupted.title": "upload interrompu",
|
|
377
|
+
"upload.jobCancelled": "job annul\xE9",
|
|
378
|
+
"upload.jobFailedDuring": "le job a \xE9chou\xE9 pendant l'upload{suffix}",
|
|
379
|
+
"upload.localRate": "d\xE9bit local : ",
|
|
380
|
+
"upload.title": "envoi direct vers l'environnement",
|
|
381
|
+
"upload.verifying": "v\xE9rification du fichier sur l'environnement\u2026",
|
|
382
|
+
"upload.waiting": "r\xE9servation de l'environnement et ouverture du canal\u2026",
|
|
383
|
+
"upload.warnKeepAlive": "\u26A0 garde ta machine allum\xE9e et ta connexion stable \u2014 si l'envoi est interrompu, le job est coup\xE9.",
|
|
384
|
+
"watch.buildPrefix": "build ",
|
|
385
|
+
"watch.cancel.confirm": "annuler ce job pour de bon ?",
|
|
386
|
+
"watch.cancel.confirmKeys": "x/y confirmer \xB7 n ou \xE9chap annuler",
|
|
387
|
+
"watch.cancel.error": "\xE9chec de la demande d\u2019annulation \u2014 r\xE9essayez avec x",
|
|
388
|
+
"watch.cancel.sent": "annulation demand\xE9e \u2014 arr\xEAt de l'environnement en cours\u2026",
|
|
389
|
+
"watch.eventStream": "flux d'\xE9v\xE9nements",
|
|
390
|
+
"watch.keycap.cancelBuild": "annuler le build",
|
|
391
|
+
"watch.status.bootstrapping": "pr\xE9paration de l'environnement",
|
|
392
|
+
"watch.status.cancelled": "annul\xE9",
|
|
393
|
+
"watch.status.created": "cr\xE9\xE9",
|
|
394
|
+
"watch.status.failed": "\xE9chou\xE9",
|
|
395
|
+
"watch.status.provisioning": "r\xE9servation de l'environnement",
|
|
396
|
+
"watch.status.running": "agent sumdae au travail",
|
|
397
|
+
"watch.status.starting": "d\xE9marrage de l'environnement",
|
|
398
|
+
"watch.status.succeeded": "termin\xE9 \u2713",
|
|
399
|
+
"watch.status.terminating": "arr\xEAt en cours",
|
|
400
|
+
"whoami.loading": "profil\u2026",
|
|
401
|
+
"whoami.machine.unknownIp": "ip inconnue",
|
|
402
|
+
"whoami.org.none": "\u2014 aucune",
|
|
403
|
+
"whoami.org.noneSwitch": "\u2014 aucune (sumdae org switch)",
|
|
404
|
+
"whoami.row.email": "email",
|
|
405
|
+
"whoami.row.machine": "machine",
|
|
406
|
+
"whoami.row.org": "org",
|
|
407
|
+
"whoami.row.session": "session",
|
|
408
|
+
"whoami.row.user": "user",
|
|
409
|
+
"whoami.session.apiKey": "cl\xE9 API",
|
|
410
|
+
"whoami.session.oauthExpires": "oauth \xB7 access token expire \xE0 {time}",
|
|
411
|
+
"whoami.unreachable": "profil inaccessible"
|
|
412
|
+
},
|
|
413
|
+
en: {
|
|
414
|
+
"agentFeed.agent.subagent": "subagent {n}",
|
|
415
|
+
"agentFeed.agent.sumdae": "sumdae agent",
|
|
416
|
+
"agentFeed.diff.moreLines": "\u2026 ({n} more lines)",
|
|
417
|
+
"agentFeed.lagged": "\u2026 (stream caught up)",
|
|
418
|
+
"agentFeed.result.failed": "failed",
|
|
419
|
+
"agentFeed.result.ok": "ok",
|
|
420
|
+
"agentFeed.shell": "shell",
|
|
421
|
+
"api.authRequired": "session expired or missing \u2014 run `sumdae login`",
|
|
422
|
+
"api.permissionDenied": "You don't have permission to perform this action.",
|
|
423
|
+
"api.quotaInsufficient": "insufficient build quota: {remaining} remaining, {needed} required",
|
|
424
|
+
"api.quotaInvalidResponse": "invalid quota response \u2014 can't verify, refused as a precaution",
|
|
425
|
+
"api.tokenExchangeFailed": "token exchange failed",
|
|
426
|
+
"banner.tagline": "the sumdae platform, from the terminal",
|
|
427
|
+
"buildCmd.buildLaunched": "build {buildId} started \u2014 quota consumed",
|
|
428
|
+
"buildCmd.cancelRequested": "cancellation requested \u2014 watching until full shutdown:",
|
|
429
|
+
"buildCmd.commandSent": "command \u201C{action}\u201D sent to {agent}",
|
|
430
|
+
"buildCmd.invalidAction": "invalid action \u2014 'kill' or 'message'",
|
|
431
|
+
"buildCmd.noActiveOrgForCancel": "no active organization",
|
|
432
|
+
"buildCmd.simEmpty": 'empty task \u2014 give the master an instruction, e.g. sumdae simulate "create /workspace/hello.txt and list the folder"',
|
|
433
|
+
"buildCmd.simLaunched": "simulation {buildId} started \u2014 quota consumed \xB7 pod rented, agents at work",
|
|
434
|
+
"buildSummary.heading": "job summary",
|
|
435
|
+
"buildSummary.rewatch": "Replay the full stream",
|
|
436
|
+
"buildSummary.rewatch.hint": "replay the events",
|
|
437
|
+
"buildSummary.watchLive": "View the running job",
|
|
438
|
+
"buildWatch.connectionLost": "lost connection to the build (30 attempts) \u2014 re-run `sumdae watch`",
|
|
439
|
+
"buildWatch.refused": "watch refused (HTTP {status})",
|
|
440
|
+
"cli.agent.description": "control a build's agents",
|
|
441
|
+
"cli.agent.kill.description": "stop an agent (default: master)",
|
|
442
|
+
"cli.agent.msg.description": "send a message to a running agent",
|
|
443
|
+
"cli.agent.opt.agent": "master | subagent-N | all",
|
|
444
|
+
"cli.build.description": "start a Docker build (consumes 1 quota) and follow live",
|
|
445
|
+
"cli.build.opt.pipeline": "pipeline artifact to integrate",
|
|
446
|
+
"cli.cancel.description": "cancel a build (environment released, quota refunded if nothing started)",
|
|
447
|
+
"cli.login.description": "sign in to sumdae (OAuth + PKCE)",
|
|
448
|
+
"cli.login.opt.noBrowser": "print the URL instead of opening the browser",
|
|
449
|
+
"cli.login.opt.withKey": "paste an API key lab_\u2026 (headless)",
|
|
450
|
+
"cli.logout.description": "sign out",
|
|
451
|
+
"cli.org.description": "manage organizations",
|
|
452
|
+
"cli.org.list.description": "list your organizations",
|
|
453
|
+
"cli.org.switch.description": "switch the active organization",
|
|
454
|
+
"cli.push.description": "upload weights or a pipeline to the active organization",
|
|
455
|
+
"cli.push.opt.kind": "weights | pipeline (inferred from the extension otherwise)",
|
|
456
|
+
"cli.quota.description": "remaining builds of the active organization",
|
|
457
|
+
"cli.root.description": "sumdae platform CLI",
|
|
458
|
+
"cli.simulate.description": "start a SIMULATION build \u2014 no model/pipeline needed (consumes 1 quota)",
|
|
459
|
+
"cli.uninstall.description": "cleanly remove sumdae from this machine (all channels)",
|
|
460
|
+
"cli.uninstall.opt.yes": "don't ask for confirmation (headless)",
|
|
461
|
+
"cli.watch.description": "follow a running build (real-time WS)",
|
|
462
|
+
"cli.whoami.description": "profile + active organization",
|
|
463
|
+
"common.activeOrgLabel": "active organization:",
|
|
464
|
+
"common.activeOrgSet": "active organization: {name}",
|
|
465
|
+
"common.back": "Go back",
|
|
466
|
+
"common.backToHome": "Back to home",
|
|
467
|
+
"common.connectedAs": "signed in: {email}",
|
|
468
|
+
"common.creatingJob": "creating job\u2026",
|
|
469
|
+
"common.jobImpossible": "job failed",
|
|
470
|
+
"common.loginFailed": "sign-in failed",
|
|
471
|
+
"common.noActiveOrgRunSwitch": "no active organization \u2014 run `sumdae org switch`",
|
|
472
|
+
"common.noOrgCreateOnLab": "no organization \u2014 create one on lab.sumdae.fr",
|
|
473
|
+
"common.orEscape": "or Esc",
|
|
474
|
+
"common.quit": "Quit",
|
|
475
|
+
"common.signingOut": "signing out\u2026",
|
|
476
|
+
"common.terminalCurrent": "(current: {cols}\xD7{rows})",
|
|
477
|
+
"common.terminalEnlarge": "Enlarge to at least {cols}\xD7{rows}",
|
|
478
|
+
"common.terminalTooSmall": "Terminal too small",
|
|
479
|
+
"common.truncated": "\u2026 (truncated)",
|
|
480
|
+
"common.waitingBrowserLogin": "waiting for browser sign-in\u2026",
|
|
481
|
+
"credentials.keychainFallback": "\u26A0 system keychain unavailable \u2014 credentials stored in {path} (chmod 600)",
|
|
482
|
+
"credentials.keyringUnavailable": "\u26A0 system keychain unavailable \u2014 credentials stored in {filePath} (chmod 600)",
|
|
483
|
+
"directUpload.err.refused": "upload refused by the environment (HTTP {status})",
|
|
484
|
+
"help.build": "start a build + live tracking",
|
|
485
|
+
"help.cancel": "cancel a build cleanly",
|
|
486
|
+
"help.heading": "COMMANDS \xB7 v{version}",
|
|
487
|
+
"help.login": "sign in (OAuth + PKCE)",
|
|
488
|
+
"help.logout": "sign out",
|
|
489
|
+
"help.push": "upload weights/pipeline (R2)",
|
|
490
|
+
"help.quota": "remaining builds of the active org",
|
|
491
|
+
"help.watch": "follow a running build",
|
|
492
|
+
"home.actions": "actions",
|
|
493
|
+
"home.job.kind.build": "build",
|
|
494
|
+
"home.job.kind.sim": "sim",
|
|
495
|
+
"home.loadingHistory": "loading history\u2026",
|
|
496
|
+
"home.menu.job": "Start a job",
|
|
497
|
+
"home.menu.job.hint": "integrate a model (Hugging Face or local file)",
|
|
498
|
+
"home.menu.lang.hint": "\u2190/\u2192 to switch",
|
|
499
|
+
"home.menu.logout": "Sign out",
|
|
500
|
+
"home.menu.orgs": "Switch organization",
|
|
501
|
+
"home.menu.quota": "Build quota",
|
|
502
|
+
"home.menu.quota.hint": "builds remaining",
|
|
503
|
+
"home.menu.refresh": "Refresh history",
|
|
504
|
+
"home.menu.simulate": "Start a simulation",
|
|
505
|
+
"home.menu.simulate.hint": "free task \u2014 dry-run of the full pipeline",
|
|
506
|
+
"home.menu.uninstall": "Uninstall sumdae",
|
|
507
|
+
"home.menu.uninstall.hint": "remove the CLI from this machine",
|
|
508
|
+
"home.menu.whoami": "Who am I",
|
|
509
|
+
"home.menu.whoami.hint": "full profile",
|
|
510
|
+
"home.noActiveOrg": "\u2014 no organization",
|
|
511
|
+
"home.noJobsYet": "no jobs yet \u2014 start a simulation to begin",
|
|
512
|
+
"home.recentJobs": "recent jobs",
|
|
513
|
+
"home.sessionLabel": "session: {session}",
|
|
514
|
+
"home.static.orgLine": "organization: {name}",
|
|
515
|
+
"home.static.orgNone": "organization: \u2014 (sumdae org switch)",
|
|
516
|
+
"home.static.sessionApiKey": "session: API key",
|
|
517
|
+
"home.static.sessionOauth": "session: oauth",
|
|
518
|
+
"job.fetching": "fetching job\u2026",
|
|
519
|
+
"job.file.err.empty.title": "empty file",
|
|
520
|
+
"job.file.err.notFile.detail": "{path} is a folder \u2014 provide a weights file or an archive.",
|
|
521
|
+
"job.file.err.notFile.title": "not a file",
|
|
522
|
+
"job.file.err.notFound.title": "file not found",
|
|
523
|
+
"job.file.placeholder": "e.g. ~/models/mistral-7b.safetensors or ./weights.tar.gz",
|
|
524
|
+
"job.file.title": "Weights file / local archive",
|
|
525
|
+
"job.fileConfirm.changeFile": "Change file",
|
|
526
|
+
"job.fileConfirm.fileLabel": "file: ",
|
|
527
|
+
"job.fileConfirm.gotItLaunch": "Got it \u2014 start the job",
|
|
528
|
+
"job.fileConfirm.title": "direct upload to the environment",
|
|
529
|
+
"job.fileConfirm.warnDirect": "\u26A0 the file is streamed DIRECTLY from this machine to the environment (it passes through no intermediate server).",
|
|
530
|
+
"job.fileConfirm.warnKeepAlive": "keep your machine on and your connection stable for the whole upload: if the connection drops, the job is cut automatically.",
|
|
531
|
+
"job.hf.checking": "checking Hugging Face access\u2026",
|
|
532
|
+
"job.hf.err.checkFailed.title": "Hugging Face check failed",
|
|
533
|
+
"job.hf.err.gated.detail": "The repo is gated: accept its terms on huggingface.co with the token's account, or check that the token has read access.",
|
|
534
|
+
"job.hf.err.gated.title": "access denied to this model",
|
|
535
|
+
"job.hf.err.invalidToken.detail": "The token configured for your organization is invalid or revoked \u2014 update it in lab.sumdae.fr \u2192 \u201COrg. settings\u201D.",
|
|
536
|
+
"job.hf.err.invalidToken.title": "Hugging Face token invalid",
|
|
537
|
+
"job.hf.err.noToken.detail": "Your organization has no Hugging Face token configured.\nAdd a READ token: lab.sumdae.fr \u2192 account menu (bottom of the sidebar) \u2192 \u201COrg. settings\u201D \u2192 Hugging Face token.\nCreate the token on huggingface.co \u2192 Settings \u2192 Access Tokens (Read).",
|
|
538
|
+
"job.hf.err.noToken.title": "Hugging Face token missing",
|
|
539
|
+
"job.hf.err.notFound.detail": "Repo or revision doesn't exist on Hugging Face \u2014 or a private repo invisible to this token. Check the link.",
|
|
540
|
+
"job.hf.err.notFound.title": "model not found",
|
|
541
|
+
"job.hf.invalidRef.detail": "Accepted formats: owner/repo, owner/repo@revision, or a full huggingface.co URL.",
|
|
542
|
+
"job.hf.invalidRef.title": "invalid reference",
|
|
543
|
+
"job.hf.noToken": "no HF token configured \u2014 add one in Org. settings on lab.sumdae.fr",
|
|
544
|
+
"job.hf.placeholder": "e.g. mistralai/Mistral-7B-v0.1, owner/repo@rev, or a huggingface.co URL",
|
|
545
|
+
"job.hf.title": "Hugging Face model",
|
|
546
|
+
"job.hf.tokenLabel": "HF token: ",
|
|
547
|
+
"job.hf.tokenMasked": "({masked})",
|
|
548
|
+
"job.hfConfirm.editLink": "Edit the link",
|
|
549
|
+
"job.hfConfirm.explain": "the model will be downloaded on the environment, integrated into the template, tested, then the Docker image will be published. 1 build of quota will be consumed.",
|
|
550
|
+
"job.hfConfirm.gated": "\xB7 gated repo (access granted)",
|
|
551
|
+
"job.hfConfirm.launch": "Start the job",
|
|
552
|
+
"job.hfConfirm.repo": "repo: ",
|
|
553
|
+
"job.hfConfirm.sizeEstimate": "estimated size: ",
|
|
554
|
+
"job.hfConfirm.sizeUnknown": "unknown",
|
|
555
|
+
"job.hfConfirm.title": "model verified \u2014 access OK",
|
|
556
|
+
"job.noUploadToken": "server response without upload_token",
|
|
557
|
+
"job.notFound": "job not found",
|
|
558
|
+
"job.source.file": "Local file",
|
|
559
|
+
"job.source.file.hint": "streamed from this machine to the environment",
|
|
560
|
+
"job.source.hf": "Hugging Face link",
|
|
561
|
+
"job.source.hf.hint": "downloaded directly on the environment (org token required)",
|
|
562
|
+
"job.source.question": "where do the model weights to integrate come from?",
|
|
563
|
+
"job.source.title": "start a job",
|
|
564
|
+
"jobLine.relative.daysAgo": "{n} d ago",
|
|
565
|
+
"jobLine.relative.hoursAgo": "{n} h ago",
|
|
566
|
+
"jobLine.relative.minutesAgo": "{n} min ago",
|
|
567
|
+
"jobLine.relative.secondsAgo": "{n} s ago",
|
|
568
|
+
"jobSummary.costAgentValue": "{cost} \xB7 {calls} call(s)",
|
|
569
|
+
"jobSummary.row.costAgent": "agent cost",
|
|
570
|
+
"jobSummary.row.costEnv": "environment cost",
|
|
571
|
+
"jobSummary.row.costTotal": "total cost",
|
|
572
|
+
"jobSummary.row.duration": "duration",
|
|
573
|
+
"jobSummary.row.environment": "environment",
|
|
574
|
+
"jobSummary.row.error": "error",
|
|
575
|
+
"jobSummary.row.status": "status",
|
|
576
|
+
"jobSummary.row.task": "task",
|
|
577
|
+
"jobSummary.row.type": "type",
|
|
578
|
+
"jobSummary.row.weights": "weights",
|
|
579
|
+
"jobSummary.type.build": "build",
|
|
580
|
+
"jobSummary.type.simulation": "simulation",
|
|
581
|
+
"keycaps.back": "back",
|
|
582
|
+
"keycaps.cancel": "cancel",
|
|
583
|
+
"keycaps.checkAccess": "check access",
|
|
584
|
+
"keycaps.escBack": "back",
|
|
585
|
+
"keycaps.navigate": "navigate",
|
|
586
|
+
"keycaps.newline": "new line",
|
|
587
|
+
"keycaps.send": "send",
|
|
588
|
+
"keycaps.switchZone": "switch zone",
|
|
589
|
+
"keycaps.validate": "confirm",
|
|
590
|
+
"landing.howConnect": "how do you want to sign in?",
|
|
591
|
+
"landing.menu.browser": "Sign in via browser",
|
|
592
|
+
"landing.menu.browser.hint": "OAuth + PKCE",
|
|
593
|
+
"landing.menu.key": "Paste an API key",
|
|
594
|
+
"landing.menu.key.hint": "lab_\u2026 \xB7 headless",
|
|
595
|
+
"landing.menu.later": "Later",
|
|
596
|
+
"landing.menu.later.hint": "`sumdae login` whenever you want",
|
|
597
|
+
"login.browser.copyUrl": "if nothing opens, copy this URL:",
|
|
598
|
+
"login.browser.openUrl": "open this URL to sign in:",
|
|
599
|
+
"login.connectedBody": "You can close this tab and return to the terminal.",
|
|
600
|
+
"login.connectedTitle": "\u2713 Signed in",
|
|
601
|
+
"login.err.invalidState": "invalid state (possible CSRF) \u2014 flow aborted",
|
|
602
|
+
"login.err.missingCode": "missing code in the callback",
|
|
603
|
+
"login.err.noBrowserResponse": "no response from the browser after {min} min",
|
|
604
|
+
"login.err.serverRefused": "refused by the identity server: {error}",
|
|
605
|
+
"login.failedTitle": "\u2717 Sign-in failed",
|
|
606
|
+
"login.invalidKey": "invalid API key",
|
|
607
|
+
"login.key.placeholder": "lab_\u2026",
|
|
608
|
+
"login.key.prompt": "API key (lab_\u2026): ",
|
|
609
|
+
"login.key.title": "API key",
|
|
610
|
+
"login.noKeyProvided": "no key provided",
|
|
611
|
+
"login.noOrgCreateThenSwitch": "pick an organization with `sumdae org switch` (TTY)",
|
|
612
|
+
"login.nonInteractiveTty": "non-interactive terminal \u2014 use `sumdae login --no-browser` in a TTY, or `--with-key`",
|
|
613
|
+
"login.validatingKey": "validating key\u2026",
|
|
614
|
+
"logout.done": "signed out",
|
|
615
|
+
"memory.duplicate": "LESSON ALREADY KNOWN",
|
|
616
|
+
"memory.query": "MEMORY",
|
|
617
|
+
"memory.resultHit": "LESSON FOUND",
|
|
618
|
+
"memory.resultMiss": "NOTHING IN MEMORY",
|
|
619
|
+
"memory.saved": "LESSON SAVED",
|
|
620
|
+
"memory.scorePrefix": "score {score} ",
|
|
621
|
+
"noOrg.continue": "Continue without organization",
|
|
622
|
+
"noOrg.createThenReturn": "create one on lab.sumdae.fr then come back here.",
|
|
623
|
+
"noOrg.none": "no organization linked to this account.",
|
|
624
|
+
"noOrg.retry": "Retry",
|
|
625
|
+
"noOrg.retry.hint": "reload your organizations",
|
|
626
|
+
"orgs.fetchFailed": "could not fetch organizations",
|
|
627
|
+
"orgs.loading": "loading organizations\u2026",
|
|
628
|
+
"orgs.nonInteractiveTty": "non-interactive terminal \u2014 can't pick an organization",
|
|
629
|
+
"orgs.role.member": "member",
|
|
630
|
+
"progress.build": "BUILD",
|
|
631
|
+
"progress.download": "DOWNLOAD",
|
|
632
|
+
"progress.elapsed": " \xB7 {duration} elapsed",
|
|
633
|
+
"progress.generic": "STEP",
|
|
634
|
+
"progress.inProgress": "in progress",
|
|
635
|
+
"progress.install": "INSTALL",
|
|
636
|
+
"progress.push": "PUSH IMAGE",
|
|
637
|
+
"progress.transferred": " transferred",
|
|
638
|
+
"progress.waitingNetwork": " \xB7 waiting for network\u2026 {duration}",
|
|
639
|
+
"promptBox.hint": "enter = send \xB7 \\ + enter = new line \xB7 esc = back",
|
|
640
|
+
"push.failed.title": "push failed",
|
|
641
|
+
"push.hashing": "sha256 of {filePath}\u2026",
|
|
642
|
+
"push.inferKindFailed": "can't infer the type \u2014 specify --kind weights or --kind pipeline",
|
|
643
|
+
"push.uploaded": "artifact uploaded",
|
|
644
|
+
"quota.exhausted": "quota exhausted \u2014 ask the admin to raise build_quota",
|
|
645
|
+
"quota.loading": "build quota\u2026",
|
|
646
|
+
"quota.row.note": "note",
|
|
647
|
+
"quota.row.remaining": "builds remaining",
|
|
648
|
+
"quota.unreachable": "build quota unavailable",
|
|
649
|
+
"selectList.hint": "\u2191\u2193 navigate \xB7 enter confirm",
|
|
650
|
+
"simulate.creating": "creating simulation\u2026",
|
|
651
|
+
"simulate.impossible": "simulation failed",
|
|
652
|
+
"simulate.placeholder": "e.g. create /workspace/hello.txt with \u201Chello\u201D and list the folder",
|
|
653
|
+
"simulate.title": "Task for the master \xB7 SIMULATION mode",
|
|
654
|
+
"uninstall.cancel": "Cancel",
|
|
655
|
+
"uninstall.cancel.hint": "delete nothing",
|
|
656
|
+
"uninstall.channel.binary": "binary",
|
|
657
|
+
"uninstall.channel.npm": "npm (global)",
|
|
658
|
+
"uninstall.channel.selfhosted": "self-hosted",
|
|
659
|
+
"uninstall.cli.cancelled": "cancelled.",
|
|
660
|
+
"uninstall.cli.channel": " channel : {channel}",
|
|
661
|
+
"uninstall.cli.cleaned": "config and credentials cleaned; the install will be erased on close.",
|
|
662
|
+
"uninstall.cli.config": " config : {configDir}",
|
|
663
|
+
"uninstall.cli.credentials": " credentials : keychain + file",
|
|
664
|
+
"uninstall.cli.heading": "Uninstalling sumdae:",
|
|
665
|
+
"uninstall.cli.installGlobal": "npm uninstall -g (global)",
|
|
666
|
+
"uninstall.cli.installLine": " install : {install}",
|
|
667
|
+
"uninstall.cli.installManual": " install : manual \u2192 {hint}",
|
|
668
|
+
"uninstall.cli.launcher": " launcher : {launcher}",
|
|
669
|
+
"uninstall.cli.manualFallback": "to do manually",
|
|
670
|
+
"uninstall.cli.stepFailed": "failed",
|
|
671
|
+
"uninstall.close": "Close",
|
|
672
|
+
"uninstall.config.now": "{configDir} (now)",
|
|
673
|
+
"uninstall.confirm.title": "Uninstall sumdae",
|
|
674
|
+
"uninstall.confirm.warning": "this will permanently remove the CLI and all its data from this machine:",
|
|
675
|
+
"uninstall.confirmDelete": "Yes, delete everything",
|
|
676
|
+
"uninstall.credentials.keychainFileNow": "keychain + file (now)",
|
|
677
|
+
"uninstall.install.atClose": "{root} (on close)",
|
|
678
|
+
"uninstall.install.manual": "\u26A0 manual \u2192 {hint}",
|
|
679
|
+
"uninstall.install.npmAtClose": "npm uninstall -g @sumdaelive/cli (on close)",
|
|
680
|
+
"uninstall.report.done": "config and credentials removed. sumdae will be erased when you close this terminal.",
|
|
681
|
+
"uninstall.report.someFailed": "some deletions failed \u2014 see above.",
|
|
682
|
+
"uninstall.report.title": "Uninstall",
|
|
683
|
+
"uninstall.row.channel": "channel",
|
|
684
|
+
"uninstall.row.config": "config",
|
|
685
|
+
"uninstall.row.credentials": "credentials",
|
|
686
|
+
"uninstall.row.install": "install",
|
|
687
|
+
"uninstall.scheduleFailed": "scheduling failed ({err}) \u2014 manual: {manual}",
|
|
688
|
+
"uninstall.working": "deleting\u2026",
|
|
689
|
+
"update.doneRestarting": "\u2713 installed \u2014 restarting\u2026",
|
|
690
|
+
"update.downloading": "downloading\u2026",
|
|
691
|
+
"update.err.extractFailed": "tar extraction failed",
|
|
692
|
+
"update.err.invalidSignature": "invalid signature \u2014 update refused",
|
|
693
|
+
"update.err.npmFailed": "npm install failed",
|
|
694
|
+
"update.err.sha256Mismatch": "tarball sha256 doesn't match",
|
|
695
|
+
"update.failed": "update failed",
|
|
696
|
+
"update.forcedFailed": "This version ({current}) is no longer supported and the update failed: {err}\nRetry, or reinstall: https://lab.sumdae.fr/cli",
|
|
697
|
+
"update.installing": "installing\u2026",
|
|
698
|
+
"update.screen.title": "Update",
|
|
699
|
+
"update.verifyingSignature": "verifying signature\u2026",
|
|
700
|
+
"upload.bytesSent": "({bytes} sent)",
|
|
701
|
+
"upload.cancelledBeforeStart": "cancelled before the upload started \u2014 the job will be cut automatically server-side (quota refunded).",
|
|
702
|
+
"upload.connInterrupted": "connection interrupted during the upload \u2014 the job will be cut server-side ({detail})",
|
|
703
|
+
"upload.envNotReady": "the environment wasn't ready in time to receive the file",
|
|
704
|
+
"upload.envRate": "environment rate: ",
|
|
705
|
+
"upload.err.cancelled": "upload cancelled",
|
|
706
|
+
"upload.err.missingEtag": "missing ETag in R2 response",
|
|
707
|
+
"upload.err.missingPresigned": "missing presigned URL for part {n}",
|
|
708
|
+
"upload.err.partFailed": "part {n}/{total} failed after {tries} attempts: {msg}",
|
|
709
|
+
"upload.etaLabel": "estimated time remaining: ",
|
|
710
|
+
"upload.interrupted.title": "upload interrupted",
|
|
711
|
+
"upload.jobCancelled": "job cancelled",
|
|
712
|
+
"upload.jobFailedDuring": "the job failed during the upload{suffix}",
|
|
713
|
+
"upload.localRate": "local rate: ",
|
|
714
|
+
"upload.title": "direct upload to the environment",
|
|
715
|
+
"upload.verifying": "verifying the file on the environment\u2026",
|
|
716
|
+
"upload.waiting": "reserving the environment and opening the channel\u2026",
|
|
717
|
+
"upload.warnKeepAlive": "\u26A0 keep your machine on and your connection stable \u2014 if the upload is interrupted, the job is cut.",
|
|
718
|
+
"watch.buildPrefix": "build ",
|
|
719
|
+
"watch.cancel.confirm": "cancel this job for good?",
|
|
720
|
+
"watch.cancel.confirmKeys": "x/y confirm \xB7 n or esc cancel",
|
|
721
|
+
"watch.cancel.error": "cancellation request failed \u2014 retry with x",
|
|
722
|
+
"watch.cancel.sent": "cancellation requested \u2014 shutting down the environment\u2026",
|
|
723
|
+
"watch.eventStream": "event stream",
|
|
724
|
+
"watch.keycap.cancelBuild": "cancel the build",
|
|
725
|
+
"watch.status.bootstrapping": "preparing the environment",
|
|
726
|
+
"watch.status.cancelled": "cancelled",
|
|
727
|
+
"watch.status.created": "created",
|
|
728
|
+
"watch.status.failed": "failed",
|
|
729
|
+
"watch.status.provisioning": "reserving the environment",
|
|
730
|
+
"watch.status.running": "sumdae agent at work",
|
|
731
|
+
"watch.status.starting": "starting the environment",
|
|
732
|
+
"watch.status.succeeded": "done \u2713",
|
|
733
|
+
"watch.status.terminating": "shutting down",
|
|
734
|
+
"whoami.loading": "profile\u2026",
|
|
735
|
+
"whoami.machine.unknownIp": "unknown ip",
|
|
736
|
+
"whoami.org.none": "\u2014 none",
|
|
737
|
+
"whoami.org.noneSwitch": "\u2014 none (sumdae org switch)",
|
|
738
|
+
"whoami.row.email": "email",
|
|
739
|
+
"whoami.row.machine": "machine",
|
|
740
|
+
"whoami.row.org": "org",
|
|
741
|
+
"whoami.row.session": "session",
|
|
742
|
+
"whoami.row.user": "user",
|
|
743
|
+
"whoami.session.apiKey": "API key",
|
|
744
|
+
"whoami.session.oauthExpires": "oauth \xB7 access token expires at {time}",
|
|
745
|
+
"whoami.unreachable": "profile unavailable"
|
|
746
|
+
}
|
|
747
|
+
};
|
|
748
|
+
|
|
749
|
+
// src/i18n.ts
|
|
750
|
+
function detectSystemLocale(env = process.env) {
|
|
751
|
+
const raw = env.LC_ALL || env.LC_MESSAGES || env.LANG || "";
|
|
752
|
+
return /^fr/i.test(raw.trim()) ? "fr" : "en";
|
|
753
|
+
}
|
|
754
|
+
var cache = null;
|
|
755
|
+
function getLocale() {
|
|
756
|
+
if (cache) return cache;
|
|
757
|
+
const cfg = loadConfig();
|
|
758
|
+
if (cfg.locale === "fr" || cfg.locale === "en") {
|
|
759
|
+
cache = cfg.locale;
|
|
760
|
+
return cache;
|
|
761
|
+
}
|
|
762
|
+
const detected = detectSystemLocale();
|
|
763
|
+
cache = detected;
|
|
764
|
+
try {
|
|
765
|
+
saveConfig({ ...loadConfig(), locale: detected });
|
|
766
|
+
} catch {
|
|
767
|
+
}
|
|
768
|
+
return cache;
|
|
769
|
+
}
|
|
770
|
+
function setLocale(l) {
|
|
771
|
+
cache = l;
|
|
772
|
+
try {
|
|
773
|
+
saveConfig({ ...loadConfig(), locale: l });
|
|
774
|
+
} catch {
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
function t(key, vars) {
|
|
778
|
+
const loc = getLocale();
|
|
779
|
+
const raw = CATALOG[loc]?.[key] ?? CATALOG.fr[key] ?? key;
|
|
780
|
+
if (!vars) return raw;
|
|
781
|
+
return raw.replace(
|
|
782
|
+
/\{(\w+)\}/g,
|
|
783
|
+
(m, name) => name in vars ? String(vars[name]) : m
|
|
784
|
+
);
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
// src/credentials.ts
|
|
76
788
|
var SERVICE = "sumdae-cli";
|
|
77
789
|
var ACCOUNT = "default";
|
|
78
790
|
var filePath = () => join2(configDir(), "credentials.json");
|
|
@@ -80,7 +792,7 @@ var warnedFallback = false;
|
|
|
80
792
|
function warnFallbackOnce() {
|
|
81
793
|
if (warnedFallback) return;
|
|
82
794
|
warnedFallback = true;
|
|
83
|
-
console.error(
|
|
795
|
+
console.error(t("credentials.keyringUnavailable", { filePath: filePath() }));
|
|
84
796
|
}
|
|
85
797
|
async function keyringEntry() {
|
|
86
798
|
if (process.env.SUMDAE_NO_KEYRING === "1") return null;
|
|
@@ -146,7 +858,7 @@ import { randomUUID } from "crypto";
|
|
|
146
858
|
import { arch as osArch, hostname, networkInterfaces, release, userInfo } from "os";
|
|
147
859
|
|
|
148
860
|
// src/version.ts
|
|
149
|
-
var CLI_VERSION = "0.1.
|
|
861
|
+
var CLI_VERSION = "0.1.4";
|
|
150
862
|
|
|
151
863
|
// src/system.ts
|
|
152
864
|
function getDeviceId() {
|
|
@@ -210,7 +922,7 @@ var ApiError = class extends Error {
|
|
|
210
922
|
function humanizeError(e) {
|
|
211
923
|
if (e instanceof ApiError) {
|
|
212
924
|
if (e.status === 403 || e.code === "missing_permission" || e.code === "not_member" || e.code === "forbidden") {
|
|
213
|
-
return "
|
|
925
|
+
return t("api.permissionDenied");
|
|
214
926
|
}
|
|
215
927
|
return e.message;
|
|
216
928
|
}
|
|
@@ -218,7 +930,7 @@ function humanizeError(e) {
|
|
|
218
930
|
}
|
|
219
931
|
var AuthRequiredError = class extends Error {
|
|
220
932
|
constructor() {
|
|
221
|
-
super("
|
|
933
|
+
super(t("api.authRequired"));
|
|
222
934
|
this.name = "AuthRequiredError";
|
|
223
935
|
}
|
|
224
936
|
};
|
|
@@ -241,24 +953,24 @@ async function exchangeToken(form) {
|
|
|
241
953
|
throw new ApiError(
|
|
242
954
|
res.status,
|
|
243
955
|
String(data.error ?? "unknown"),
|
|
244
|
-
String(data.error_description ?? "
|
|
956
|
+
String(data.error_description ?? t("api.tokenExchangeFailed"))
|
|
245
957
|
);
|
|
246
958
|
}
|
|
247
959
|
return data;
|
|
248
960
|
}
|
|
249
|
-
function tokenSetFromResponse(
|
|
961
|
+
function tokenSetFromResponse(t2) {
|
|
250
962
|
return {
|
|
251
963
|
kind: "oauth",
|
|
252
|
-
accessToken:
|
|
253
|
-
refreshToken:
|
|
254
|
-
expiresAt: Date.now() +
|
|
964
|
+
accessToken: t2.access_token,
|
|
965
|
+
refreshToken: t2.refresh_token,
|
|
966
|
+
expiresAt: Date.now() + t2.expires_in * 1e3
|
|
255
967
|
};
|
|
256
968
|
}
|
|
257
969
|
async function refresh(creds) {
|
|
258
970
|
if (!creds.refreshToken) throw new AuthRequiredError();
|
|
259
|
-
let
|
|
971
|
+
let t2;
|
|
260
972
|
try {
|
|
261
|
-
|
|
973
|
+
t2 = await exchangeToken({
|
|
262
974
|
grant_type: "refresh_token",
|
|
263
975
|
refresh_token: creds.refreshToken,
|
|
264
976
|
client_id: "sumdae-cli"
|
|
@@ -267,7 +979,7 @@ async function refresh(creds) {
|
|
|
267
979
|
await clearCredentials();
|
|
268
980
|
throw new AuthRequiredError();
|
|
269
981
|
}
|
|
270
|
-
const next = tokenSetFromResponse(
|
|
982
|
+
const next = tokenSetFromResponse(t2);
|
|
271
983
|
await saveCredentials(next);
|
|
272
984
|
return next;
|
|
273
985
|
}
|
|
@@ -318,7 +1030,7 @@ function parseQuota(data) {
|
|
|
318
1030
|
throw new ApiError(
|
|
319
1031
|
502,
|
|
320
1032
|
"invalid_quota_response",
|
|
321
|
-
"
|
|
1033
|
+
t("api.quotaInvalidResponse"),
|
|
322
1034
|
data
|
|
323
1035
|
);
|
|
324
1036
|
}
|
|
@@ -383,7 +1095,7 @@ function connectOnce(url, token, cursor, onEvent, signal) {
|
|
|
383
1095
|
};
|
|
384
1096
|
signal?.addEventListener("abort", close, { once: true });
|
|
385
1097
|
ws.on("unexpected-response", (_req, res) => {
|
|
386
|
-
reject(new Error(
|
|
1098
|
+
reject(new Error(t("buildWatch.refused", { status: res.statusCode ?? "?" })));
|
|
387
1099
|
close();
|
|
388
1100
|
});
|
|
389
1101
|
ws.on("error", () => {
|
|
@@ -429,16 +1141,16 @@ async function watchBuild(buildId, onEvent, opts = {}) {
|
|
|
429
1141
|
if (opts.signal?.aborted) return "cancelled-local";
|
|
430
1142
|
failures = cursor.last > before ? 0 : failures + 1;
|
|
431
1143
|
if (failures > 30) {
|
|
432
|
-
throw new Error(
|
|
1144
|
+
throw new Error(t("buildWatch.connectionLost"));
|
|
433
1145
|
}
|
|
434
1146
|
await new Promise((resolve3) => {
|
|
435
1147
|
const ms = Math.min(1e3 * (failures + 1), 1e4);
|
|
436
|
-
const
|
|
1148
|
+
const t2 = setTimeout(() => {
|
|
437
1149
|
opts.signal?.removeEventListener("abort", onAbort);
|
|
438
1150
|
resolve3();
|
|
439
1151
|
}, ms);
|
|
440
1152
|
const onAbort = () => {
|
|
441
|
-
clearTimeout(
|
|
1153
|
+
clearTimeout(t2);
|
|
442
1154
|
resolve3();
|
|
443
1155
|
};
|
|
444
1156
|
opts.signal?.addEventListener("abort", onAbort, { once: true });
|
|
@@ -595,7 +1307,7 @@ function AgentEventRow({ ev }) {
|
|
|
595
1307
|
] });
|
|
596
1308
|
case "agent": {
|
|
597
1309
|
const raw = String(data.agent ?? "agent");
|
|
598
|
-
const displayName = raw === "master" ? "agent
|
|
1310
|
+
const displayName = raw === "master" ? t("agentFeed.agent.sumdae") : raw.startsWith("subagent-") ? `sous-agent ${raw.slice("subagent-".length)}` : raw;
|
|
599
1311
|
return /* @__PURE__ */ jsxs(Box, { children: [
|
|
600
1312
|
/* @__PURE__ */ jsx(Text, { color: COLORS.zinc500, children: "\u25CF" }),
|
|
601
1313
|
/* @__PURE__ */ jsx(Text, { children: " " }),
|
|
@@ -611,7 +1323,7 @@ function AgentEventRow({ ev }) {
|
|
|
611
1323
|
return /* @__PURE__ */ jsxs(Box, { marginTop: 1, children: [
|
|
612
1324
|
/* @__PURE__ */ jsx(Text, { color: isCommand ? COLORS.turquoise : COLORS.emerald, children: isCommand ? "\u25B8" : "\u25CF" }),
|
|
613
1325
|
/* @__PURE__ */ jsx(Text, { children: " " }),
|
|
614
|
-
/* @__PURE__ */ jsx(Text, { bold: true, color: COLORS.zinc100, children: isCommand ? "shell" : tool }),
|
|
1326
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: COLORS.zinc100, children: isCommand ? t("agentFeed.shell") : tool }),
|
|
615
1327
|
summary ? isCommand ? /* @__PURE__ */ jsxs(Text, { color: COLORS.turquoise, children: [
|
|
616
1328
|
" $ ",
|
|
617
1329
|
summary
|
|
@@ -624,7 +1336,7 @@ function AgentEventRow({ ev }) {
|
|
|
624
1336
|
}
|
|
625
1337
|
case "tool_result": {
|
|
626
1338
|
const ok2 = data.ok === true;
|
|
627
|
-
const msg = ev.message ?? (ok2 ? "ok" : "
|
|
1339
|
+
const msg = ev.message ?? (ok2 ? t("agentFeed.result.ok") : t("agentFeed.result.failed"));
|
|
628
1340
|
return /* @__PURE__ */ jsxs(Box, { marginLeft: 2, children: [
|
|
629
1341
|
/* @__PURE__ */ jsxs(Box, { flexShrink: 0, children: [
|
|
630
1342
|
/* @__PURE__ */ jsx(Text, { color: COLORS.zinc700, children: "\u23BF " }),
|
|
@@ -663,7 +1375,7 @@ function AgentEventRow({ ev }) {
|
|
|
663
1375
|
] })
|
|
664
1376
|
] });
|
|
665
1377
|
case "lagged":
|
|
666
|
-
return /* @__PURE__ */ jsx(Text, { color: COLORS.zinc700, dimColor: true, children: "
|
|
1378
|
+
return /* @__PURE__ */ jsx(Text, { color: COLORS.zinc700, dimColor: true, children: t("agentFeed.lagged") });
|
|
667
1379
|
default: {
|
|
668
1380
|
const level = String(data.level ?? "info");
|
|
669
1381
|
const color = level === "error" ? COLORS.red : level === "warn" ? COLORS.amber : COLORS.zinc500;
|
|
@@ -679,7 +1391,7 @@ function AgentEventRow({ ev }) {
|
|
|
679
1391
|
import { Box as Box2, Text as Text2 } from "ink";
|
|
680
1392
|
import { useEffect, useMemo, useRef, useState } from "react";
|
|
681
1393
|
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
682
|
-
var
|
|
1394
|
+
var VERBS_FR = [
|
|
683
1395
|
// espace / planète
|
|
684
1396
|
"Orbite",
|
|
685
1397
|
"Gravite",
|
|
@@ -726,6 +1438,53 @@ var VERBS = [
|
|
|
726
1438
|
"Cogite",
|
|
727
1439
|
"Trame"
|
|
728
1440
|
];
|
|
1441
|
+
var VERBS_EN = [
|
|
1442
|
+
// space / planet
|
|
1443
|
+
"Orbiting",
|
|
1444
|
+
"Gravitating",
|
|
1445
|
+
"Propelling",
|
|
1446
|
+
"Lifting off",
|
|
1447
|
+
"Landing",
|
|
1448
|
+
"Docking",
|
|
1449
|
+
"Mooring",
|
|
1450
|
+
"Mapping",
|
|
1451
|
+
"Constellating",
|
|
1452
|
+
"Satelliting",
|
|
1453
|
+
"Hyperspacing",
|
|
1454
|
+
"Aligning the stars",
|
|
1455
|
+
"Terraforming",
|
|
1456
|
+
// docker / build
|
|
1457
|
+
"Containerizing",
|
|
1458
|
+
"Dockerizing",
|
|
1459
|
+
"Stacking layers",
|
|
1460
|
+
"Compiling",
|
|
1461
|
+
"Assembling",
|
|
1462
|
+
"Welding",
|
|
1463
|
+
"Forging",
|
|
1464
|
+
"Tagging",
|
|
1465
|
+
"Pushing to registry",
|
|
1466
|
+
"Smoke-testing",
|
|
1467
|
+
"Scaffolding",
|
|
1468
|
+
"Setting the Dockerfile",
|
|
1469
|
+
// models / pipelines
|
|
1470
|
+
"Tensing the tensors",
|
|
1471
|
+
"Vectorizing",
|
|
1472
|
+
"Quantizing",
|
|
1473
|
+
"Distilling",
|
|
1474
|
+
"Waking the weights",
|
|
1475
|
+
"Warming the pipeline",
|
|
1476
|
+
"Calibrating",
|
|
1477
|
+
"Inferring",
|
|
1478
|
+
"Taming the model",
|
|
1479
|
+
"Wrangling the agents",
|
|
1480
|
+
// agent kitchen
|
|
1481
|
+
"Simmering",
|
|
1482
|
+
"Concocting",
|
|
1483
|
+
"Brewing",
|
|
1484
|
+
"Orchestrating",
|
|
1485
|
+
"Cogitating",
|
|
1486
|
+
"Weaving"
|
|
1487
|
+
];
|
|
729
1488
|
var TWINKLE = ["\xB7", "\u2722", "\u2733", "\u2736", "\u273B", "\u273D"];
|
|
730
1489
|
var TWINKLE_CYCLE = [...TWINKLE, ...[...TWINKLE].reverse()];
|
|
731
1490
|
var FRAME_MS = 120;
|
|
@@ -757,14 +1516,15 @@ var PLANET_MAP = [
|
|
|
757
1516
|
];
|
|
758
1517
|
var PLANET_PERIOD = 6;
|
|
759
1518
|
function pickVerb() {
|
|
760
|
-
|
|
1519
|
+
const verbs = getLocale() === "en" ? VERBS_EN : VERBS_FR;
|
|
1520
|
+
return verbs[Math.floor(Math.random() * verbs.length)];
|
|
761
1521
|
}
|
|
762
1522
|
function PlanetScene({ frame }) {
|
|
763
1523
|
const starPhase = Math.floor(frame / 2) % STAR_GLYPHS.length;
|
|
764
1524
|
const star = (i) => i === starPhase ? /* @__PURE__ */ jsx2(Text2, { color: COLORS.emerald, children: STAR_GLYPHS[i] }) : /* @__PURE__ */ jsx2(Text2, { color: COLORS.zinc700, children: "\xB7" });
|
|
765
1525
|
const rot = Math.floor(frame / PLANET_PERIOD);
|
|
766
1526
|
const mapW = PLANET_MAP[0].length;
|
|
767
|
-
const pixelColor = (
|
|
1527
|
+
const pixelColor = (t2) => t2 === 0 ? COLORS.oceanDeep : t2 === 1 ? COLORS.oceanShallow : t2 === 2 ? COLORS.land : COLORS.emeraldDim;
|
|
768
1528
|
const pixel = (x, y) => {
|
|
769
1529
|
const { start, end } = PLANET_ROWS[y];
|
|
770
1530
|
if (x < start || x >= end) return null;
|
|
@@ -774,14 +1534,14 @@ function PlanetScene({ frame }) {
|
|
|
774
1534
|
const buildRow = (yTop) => {
|
|
775
1535
|
const cells = [];
|
|
776
1536
|
for (let x = 0; x < PLANET_GRID_W; x++) {
|
|
777
|
-
const
|
|
1537
|
+
const t2 = pixel(x, yTop);
|
|
778
1538
|
const b = pixel(x, yTop + 1);
|
|
779
|
-
if (!
|
|
1539
|
+
if (!t2 && !b) {
|
|
780
1540
|
cells.push(/* @__PURE__ */ jsx2(Text2, { children: " " }, x));
|
|
781
1541
|
continue;
|
|
782
1542
|
}
|
|
783
|
-
const glyph =
|
|
784
|
-
const color = rank(
|
|
1543
|
+
const glyph = t2 && b ? "\u2588" : t2 ? "\u2580" : "\u2584";
|
|
1544
|
+
const color = rank(t2) >= rank(b) ? t2 ?? b : b;
|
|
785
1545
|
cells.push(
|
|
786
1546
|
/* @__PURE__ */ jsx2(Text2, { color, children: glyph }, x)
|
|
787
1547
|
);
|
|
@@ -822,13 +1582,13 @@ function BusyIndicator({
|
|
|
822
1582
|
const verb = useMemo(() => forcedVerb ?? pickVerb(), [forcedVerb, verbKey, label]);
|
|
823
1583
|
const withShimmer = !label;
|
|
824
1584
|
useEffect(() => {
|
|
825
|
-
const
|
|
826
|
-
return () => clearInterval(
|
|
1585
|
+
const t2 = setInterval(() => setFrame((f) => (f + 1) % TWINKLE_CYCLE.length), FRAME_MS);
|
|
1586
|
+
return () => clearInterval(t2);
|
|
827
1587
|
}, []);
|
|
828
1588
|
useEffect(() => {
|
|
829
1589
|
if (!withShimmer) return;
|
|
830
|
-
const
|
|
831
|
-
return () => clearInterval(
|
|
1590
|
+
const t2 = setInterval(() => setShimmer((s) => s + 1), SHIMMER_MS);
|
|
1591
|
+
return () => clearInterval(t2);
|
|
832
1592
|
}, [withShimmer]);
|
|
833
1593
|
const glyph = TWINKLE_CYCLE[frame];
|
|
834
1594
|
const text = label ?? `${verb}\u2026`;
|
|
@@ -902,26 +1662,26 @@ import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
|
902
1662
|
var MEMORY_ITEM_TTL_MS = 6e3;
|
|
903
1663
|
function agentLabel(raw) {
|
|
904
1664
|
if (!raw) return "";
|
|
905
|
-
if (raw === "master") return "agent
|
|
1665
|
+
if (raw === "master") return t("agentFeed.agent.sumdae");
|
|
906
1666
|
if (raw.startsWith("subagent-")) return `sous-agent ${raw.slice("subagent-".length)}`;
|
|
907
1667
|
return raw;
|
|
908
1668
|
}
|
|
909
1669
|
function clip(s, max) {
|
|
910
|
-
const
|
|
911
|
-
return
|
|
1670
|
+
const t2 = s.replace(/\s+/g, " ").trim();
|
|
1671
|
+
return t2.length > max ? `${t2.slice(0, max - 1)}\u2026` : t2;
|
|
912
1672
|
}
|
|
913
1673
|
function describe(op) {
|
|
914
1674
|
switch (op) {
|
|
915
1675
|
case "query":
|
|
916
|
-
return { icon: "\u{1F50E}", verb: "
|
|
1676
|
+
return { icon: "\u{1F50E}", verb: t("memory.query"), color: COLORS.sky };
|
|
917
1677
|
case "result_hit":
|
|
918
|
-
return { icon: "\u{1F4A1}", verb: "
|
|
1678
|
+
return { icon: "\u{1F4A1}", verb: t("memory.resultHit"), color: COLORS.amber };
|
|
919
1679
|
case "result_miss":
|
|
920
|
-
return { icon: "\u2205", verb: "
|
|
1680
|
+
return { icon: "\u2205", verb: t("memory.resultMiss"), color: COLORS.zinc500 };
|
|
921
1681
|
case "saved":
|
|
922
|
-
return { icon: "\u{1F4BE}", verb: "
|
|
1682
|
+
return { icon: "\u{1F4BE}", verb: t("memory.saved"), color: COLORS.emerald };
|
|
923
1683
|
case "duplicate":
|
|
924
|
-
return { icon: "\u2248", verb: "
|
|
1684
|
+
return { icon: "\u2248", verb: t("memory.duplicate"), color: COLORS.zinc500 };
|
|
925
1685
|
}
|
|
926
1686
|
}
|
|
927
1687
|
function MemoryRow({ item }) {
|
|
@@ -987,14 +1747,14 @@ function fmtDuration(secs) {
|
|
|
987
1747
|
function describe2(label) {
|
|
988
1748
|
const l = label.toLowerCase();
|
|
989
1749
|
if (l.includes("push") || l.includes("upload"))
|
|
990
|
-
return { icon: "\u2B06", verb: "
|
|
1750
|
+
return { icon: "\u2B06", verb: t("progress.push"), color: COLORS.opPush };
|
|
991
1751
|
if (l.includes("pull") || l.includes("download") || l.includes("wget") || l.includes("curl") || l.includes("clone") || l.includes("fetch"))
|
|
992
|
-
return { icon: "\u2B07", verb: "
|
|
1752
|
+
return { icon: "\u2B07", verb: t("progress.download"), color: COLORS.opDownload };
|
|
993
1753
|
if (l.includes("pip") || l.includes("apt") || l.includes("install"))
|
|
994
|
-
return { icon: "\u{1F4E6}", verb: "
|
|
1754
|
+
return { icon: "\u{1F4E6}", verb: t("progress.install"), color: COLORS.opInstall };
|
|
995
1755
|
if (l.includes("bazel") || l.includes("build") || l.includes("make") || l.includes("compile"))
|
|
996
|
-
return { icon: "\u2699", verb: "
|
|
997
|
-
return { icon: "\u25B8", verb: "
|
|
1756
|
+
return { icon: "\u2699", verb: t("progress.build"), color: COLORS.opBuild };
|
|
1757
|
+
return { icon: "\u25B8", verb: t("progress.generic"), color: COLORS.opGeneric };
|
|
998
1758
|
}
|
|
999
1759
|
function rateSuffix(item) {
|
|
1000
1760
|
const parts = [];
|
|
@@ -1050,15 +1810,15 @@ function ProgressRow({ item, tick }) {
|
|
|
1050
1810
|
" "
|
|
1051
1811
|
] }),
|
|
1052
1812
|
/* @__PURE__ */ jsx7(Text7, { color: COLORS.zinc100, bold: true, children: fmtBytes(item.done) }),
|
|
1053
|
-
/* @__PURE__ */
|
|
1813
|
+
/* @__PURE__ */ jsxs6(Text7, { color: COLORS.zinc400, children: [
|
|
1814
|
+
" ",
|
|
1815
|
+
t("progress.transferred")
|
|
1816
|
+
] }),
|
|
1054
1817
|
item.rate > 0 ? /* @__PURE__ */ jsxs6(Text7, { color: COLORS.zinc500, children: [
|
|
1055
1818
|
" \xB7 ",
|
|
1056
1819
|
fmtBytes(item.rate),
|
|
1057
1820
|
"/s"
|
|
1058
|
-
] }) : stalled ? /* @__PURE__ */
|
|
1059
|
-
" \xB7 en attente du r\xE9seau\u2026 ",
|
|
1060
|
-
fmtDuration(item.stalledFor ?? 0)
|
|
1061
|
-
] }) : null
|
|
1821
|
+
] }) : stalled ? /* @__PURE__ */ jsx7(Text7, { color: COLORS.amber, children: t("progress.waitingNetwork", { duration: fmtDuration(item.stalledFor ?? 0) }) }) : null
|
|
1062
1822
|
] })
|
|
1063
1823
|
) : /* @__PURE__ */ jsxs6(Text7, { children: [
|
|
1064
1824
|
/* @__PURE__ */ jsxs6(Text7, { color, children: [
|
|
@@ -1066,12 +1826,8 @@ function ProgressRow({ item, tick }) {
|
|
|
1066
1826
|
SPINNER[tick % SPINNER.length],
|
|
1067
1827
|
" "
|
|
1068
1828
|
] }),
|
|
1069
|
-
/* @__PURE__ */ jsx7(Text7, { color: COLORS.zinc300, children: "
|
|
1070
|
-
/* @__PURE__ */
|
|
1071
|
-
" \xB7 ",
|
|
1072
|
-
fmtDuration(item.done),
|
|
1073
|
-
" \xE9coul\xE9"
|
|
1074
|
-
] })
|
|
1829
|
+
/* @__PURE__ */ jsx7(Text7, { color: COLORS.zinc300, children: t("progress.inProgress") }),
|
|
1830
|
+
/* @__PURE__ */ jsx7(Text7, { color: COLORS.zinc600, children: t("progress.elapsed", { duration: fmtDuration(item.done) }) })
|
|
1075
1831
|
] })
|
|
1076
1832
|
] });
|
|
1077
1833
|
}
|
|
@@ -1225,19 +1981,19 @@ function TimelineDock({ groups, tick }) {
|
|
|
1225
1981
|
// src/commands/build.tsx
|
|
1226
1982
|
import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1227
1983
|
var STATUS_LABEL = {
|
|
1228
|
-
created: "
|
|
1229
|
-
provisioning: "
|
|
1230
|
-
starting: "
|
|
1231
|
-
bootstrapping: "
|
|
1232
|
-
running: "
|
|
1233
|
-
terminating: "
|
|
1234
|
-
succeeded: "
|
|
1235
|
-
failed: "
|
|
1236
|
-
cancelled: "
|
|
1984
|
+
created: t("watch.status.created"),
|
|
1985
|
+
provisioning: t("watch.status.provisioning"),
|
|
1986
|
+
starting: t("watch.status.starting"),
|
|
1987
|
+
bootstrapping: t("watch.status.bootstrapping"),
|
|
1988
|
+
running: t("watch.status.running"),
|
|
1989
|
+
terminating: t("watch.status.terminating"),
|
|
1990
|
+
succeeded: t("watch.status.succeeded"),
|
|
1991
|
+
failed: t("watch.status.failed"),
|
|
1992
|
+
cancelled: t("watch.status.cancelled")
|
|
1237
1993
|
};
|
|
1238
1994
|
async function requestCancel(buildId) {
|
|
1239
1995
|
const active = await resolveActiveOrg().catch(() => null);
|
|
1240
|
-
if (!active) throw new Error("
|
|
1996
|
+
if (!active) throw new Error(t("buildCmd.noActiveOrgForCancel"));
|
|
1241
1997
|
await labApi(
|
|
1242
1998
|
`/orgs/${encodeURIComponent(active.slug)}/builds/${encodeURIComponent(buildId)}/cancel`,
|
|
1243
1999
|
{ method: "POST" }
|
|
@@ -1259,12 +2015,12 @@ function normalizeTimelineStatus(s, fallback) {
|
|
|
1259
2015
|
return s === "pending" || s === "active" || s === "done" || s === "failed" ? s : fallback;
|
|
1260
2016
|
}
|
|
1261
2017
|
function truncateEvent(ev) {
|
|
1262
|
-
const message = ev.message && ev.message.length > 4e3 ? `${ev.message.slice(0, 4e3)}
|
|
2018
|
+
const message = ev.message && ev.message.length > 4e3 ? `${ev.message.slice(0, 4e3)} ${t("common.truncated")}` : ev.message;
|
|
1263
2019
|
let data = ev.data;
|
|
1264
2020
|
const patch = data?.patch;
|
|
1265
2021
|
if (typeof patch === "string" && patch.length > 8e3) {
|
|
1266
2022
|
data = { ...data, patch: `${patch.slice(0, 8e3)}
|
|
1267
|
-
|
|
2023
|
+
${t("common.truncated")}` };
|
|
1268
2024
|
}
|
|
1269
2025
|
return message === ev.message && data === ev.data ? ev : { ...ev, message, data };
|
|
1270
2026
|
}
|
|
@@ -1337,10 +2093,10 @@ function BuildWatcher({
|
|
|
1337
2093
|
(ev) => {
|
|
1338
2094
|
if (!mounted) return;
|
|
1339
2095
|
if (!startPinned.current && ev.at) {
|
|
1340
|
-
const
|
|
1341
|
-
if (Number.isFinite(
|
|
2096
|
+
const t2 = Date.parse(ev.at);
|
|
2097
|
+
if (Number.isFinite(t2)) {
|
|
1342
2098
|
startPinned.current = true;
|
|
1343
|
-
setStartedAt(
|
|
2099
|
+
setStartedAt(t2);
|
|
1344
2100
|
}
|
|
1345
2101
|
}
|
|
1346
2102
|
const s = ev.data?.status;
|
|
@@ -1507,8 +2263,8 @@ function BuildWatcher({
|
|
|
1507
2263
|
const hasSpinners = Object.keys(progress).length > 0 || memory.length > 0 || timelineGroups.some((g) => g.status === "active");
|
|
1508
2264
|
useEffect2(() => {
|
|
1509
2265
|
if (!hasSpinners) return;
|
|
1510
|
-
const
|
|
1511
|
-
return () => clearInterval(
|
|
2266
|
+
const t2 = setInterval(() => setSpinTick((n) => n + 1), 120);
|
|
2267
|
+
return () => clearInterval(t2);
|
|
1512
2268
|
}, [hasSpinners]);
|
|
1513
2269
|
useEffect2(() => {
|
|
1514
2270
|
if (!stdout) return;
|
|
@@ -1535,7 +2291,7 @@ function BuildWatcher({
|
|
|
1535
2291
|
/* @__PURE__ */ jsx9(Text9, { color: COLORS.zinc500, children: "build " }),
|
|
1536
2292
|
/* @__PURE__ */ jsx9(Text9, { color: COLORS.zinc100, bold: true, children: buildId.slice(0, 8) }),
|
|
1537
2293
|
/* @__PURE__ */ jsx9(Text9, { color: COLORS.zinc700, children: " \xB7 " }),
|
|
1538
|
-
/* @__PURE__ */ jsx9(Text9, { color: COLORS.zinc400, children: orgName ?? "
|
|
2294
|
+
/* @__PURE__ */ jsx9(Text9, { color: COLORS.zinc400, children: orgName ?? t("watch.eventStream") })
|
|
1539
2295
|
] });
|
|
1540
2296
|
const orgBlock = /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", flexShrink: 0, marginLeft: 4, alignItems: "flex-end", children: [
|
|
1541
2297
|
buildHeader,
|
|
@@ -1563,16 +2319,16 @@ function BuildWatcher({
|
|
|
1563
2319
|
// s'affichent sur la ligne JUSTE sous le chrono, dans la même
|
|
1564
2320
|
// colonne (même padding que le verbe et le timer).
|
|
1565
2321
|
(() => {
|
|
1566
|
-
const footer = cancelState === "sent" ? /* @__PURE__ */ jsx9(Text9, { color: COLORS.amber, dimColor: true, children: "
|
|
1567
|
-
"
|
|
2322
|
+
const footer = cancelState === "sent" ? /* @__PURE__ */ jsx9(Text9, { color: COLORS.amber, dimColor: true, children: t("watch.cancel.sent") }) : cancelState === "error" ? /* @__PURE__ */ jsx9(Text9, { color: COLORS.red, dimColor: true, children: t("watch.cancel.error") }) : confirmKill ? /* @__PURE__ */ jsxs8(Text9, { color: COLORS.amber, bold: true, children: [
|
|
2323
|
+
t("watch.cancel.confirm"),
|
|
1568
2324
|
" ",
|
|
1569
|
-
/* @__PURE__ */ jsx9(Text9, { color: COLORS.zinc500, children: "
|
|
2325
|
+
/* @__PURE__ */ jsx9(Text9, { color: COLORS.zinc500, children: t("watch.cancel.confirmKeys") })
|
|
1570
2326
|
] }) : /* @__PURE__ */ jsx9(
|
|
1571
2327
|
Keycaps,
|
|
1572
2328
|
{
|
|
1573
2329
|
items: [
|
|
1574
|
-
{ key: "x", desc: "
|
|
1575
|
-
{ key: "\xE9chap", desc: "
|
|
2330
|
+
{ key: "x", desc: t("watch.keycap.cancelBuild") },
|
|
2331
|
+
{ key: "\xE9chap", desc: t("keycaps.escBack") }
|
|
1576
2332
|
]
|
|
1577
2333
|
}
|
|
1578
2334
|
);
|
|
@@ -1613,18 +2369,18 @@ async function cancelAction(buildId) {
|
|
|
1613
2369
|
process.exitCode = 1;
|
|
1614
2370
|
return;
|
|
1615
2371
|
}
|
|
1616
|
-
console.log("
|
|
2372
|
+
console.log(t("buildCmd.cancelRequested"));
|
|
1617
2373
|
await watchAction(buildId);
|
|
1618
2374
|
}
|
|
1619
2375
|
async function agentCommandAction(buildId, action, opts) {
|
|
1620
2376
|
if (action !== "kill" && action !== "message") {
|
|
1621
|
-
console.error("
|
|
2377
|
+
console.error(t("buildCmd.invalidAction"));
|
|
1622
2378
|
process.exitCode = 1;
|
|
1623
2379
|
return;
|
|
1624
2380
|
}
|
|
1625
2381
|
const active = await resolveActiveOrg().catch(() => null);
|
|
1626
2382
|
if (!active) {
|
|
1627
|
-
console.error("
|
|
2383
|
+
console.error(t("common.noActiveOrgRunSwitch"));
|
|
1628
2384
|
process.exitCode = 1;
|
|
1629
2385
|
return;
|
|
1630
2386
|
}
|
|
@@ -1634,7 +2390,7 @@ async function agentCommandAction(buildId, action, opts) {
|
|
|
1634
2390
|
headers: { "content-type": "application/json" },
|
|
1635
2391
|
body: JSON.stringify({ action, agent: opts.agent ?? "master", message: opts.message })
|
|
1636
2392
|
});
|
|
1637
|
-
console.log(
|
|
2393
|
+
console.log(t("buildCmd.commandSent", { action, agent: opts.agent ?? "master" }));
|
|
1638
2394
|
} catch (e) {
|
|
1639
2395
|
console.error(e instanceof Error ? e.message : String(e));
|
|
1640
2396
|
process.exitCode = 1;
|
|
@@ -1643,7 +2399,7 @@ async function agentCommandAction(buildId, action, opts) {
|
|
|
1643
2399
|
async function buildAction(weightsArtifactId, opts) {
|
|
1644
2400
|
const active = await resolveActiveOrg().catch(() => null);
|
|
1645
2401
|
if (!active) {
|
|
1646
|
-
console.error("
|
|
2402
|
+
console.error(t("common.noActiveOrgRunSwitch"));
|
|
1647
2403
|
process.exitCode = 1;
|
|
1648
2404
|
return;
|
|
1649
2405
|
}
|
|
@@ -1666,19 +2422,19 @@ async function buildAction(weightsArtifactId, opts) {
|
|
|
1666
2422
|
process.exitCode = 1;
|
|
1667
2423
|
return;
|
|
1668
2424
|
}
|
|
1669
|
-
console.log(
|
|
2425
|
+
console.log(t("buildCmd.buildLaunched", { buildId }));
|
|
1670
2426
|
await watchAction(buildId);
|
|
1671
2427
|
}
|
|
1672
2428
|
async function simulateAction(task) {
|
|
1673
2429
|
const trimmed = task.trim();
|
|
1674
2430
|
if (!trimmed) {
|
|
1675
|
-
console.error(
|
|
2431
|
+
console.error(t("buildCmd.simEmpty"));
|
|
1676
2432
|
process.exitCode = 1;
|
|
1677
2433
|
return;
|
|
1678
2434
|
}
|
|
1679
2435
|
const active = await resolveActiveOrg().catch(() => null);
|
|
1680
2436
|
if (!active) {
|
|
1681
|
-
console.error("
|
|
2437
|
+
console.error(t("common.noActiveOrgRunSwitch"));
|
|
1682
2438
|
process.exitCode = 1;
|
|
1683
2439
|
return;
|
|
1684
2440
|
}
|
|
@@ -1698,7 +2454,7 @@ async function simulateAction(task) {
|
|
|
1698
2454
|
process.exitCode = 1;
|
|
1699
2455
|
return;
|
|
1700
2456
|
}
|
|
1701
|
-
console.log(
|
|
2457
|
+
console.log(t("buildCmd.simLaunched", { buildId }));
|
|
1702
2458
|
await watchAction(buildId);
|
|
1703
2459
|
}
|
|
1704
2460
|
|
|
@@ -1810,7 +2566,7 @@ async function uploadFileToPod(opts) {
|
|
|
1810
2566
|
} else {
|
|
1811
2567
|
reject(
|
|
1812
2568
|
new Error(
|
|
1813
|
-
|
|
2569
|
+
t("directUpload.err.refused", { status: res.statusCode ?? "?" }) + (body ? ` : ${body.slice(0, 200)}` : "")
|
|
1814
2570
|
)
|
|
1815
2571
|
);
|
|
1816
2572
|
}
|
|
@@ -1818,7 +2574,7 @@ async function uploadFileToPod(opts) {
|
|
|
1818
2574
|
}
|
|
1819
2575
|
);
|
|
1820
2576
|
const abort = () => {
|
|
1821
|
-
req.destroy(new Error("upload
|
|
2577
|
+
req.destroy(new Error(t("upload.err.cancelled")));
|
|
1822
2578
|
};
|
|
1823
2579
|
signal?.addEventListener("abort", abort, { once: true });
|
|
1824
2580
|
req.on("error", (e) => {
|
|
@@ -1944,7 +2700,7 @@ function JobUpload({
|
|
|
1944
2700
|
const d = e.data;
|
|
1945
2701
|
if (d?.status === "failed" || d?.status === "cancelled") {
|
|
1946
2702
|
fail(
|
|
1947
|
-
d.status === "failed" ?
|
|
2703
|
+
d.status === "failed" ? t("upload.jobFailedDuring", { suffix: e.message ? ` : ${e.message}` : "" }) : t("upload.jobCancelled")
|
|
1948
2704
|
);
|
|
1949
2705
|
}
|
|
1950
2706
|
}
|
|
@@ -1968,7 +2724,7 @@ function JobUpload({
|
|
|
1968
2724
|
}
|
|
1969
2725
|
if (done.current) return;
|
|
1970
2726
|
if (!url) {
|
|
1971
|
-
fail("
|
|
2727
|
+
fail(t("upload.envNotReady"));
|
|
1972
2728
|
return;
|
|
1973
2729
|
}
|
|
1974
2730
|
uploadStarted = true;
|
|
@@ -1988,7 +2744,9 @@ function JobUpload({
|
|
|
1988
2744
|
setTimeout(() => succeed(), 1e4);
|
|
1989
2745
|
} catch (e) {
|
|
1990
2746
|
fail(
|
|
1991
|
-
|
|
2747
|
+
t("upload.connInterrupted", {
|
|
2748
|
+
detail: e instanceof Error ? e.message : String(e)
|
|
2749
|
+
})
|
|
1992
2750
|
);
|
|
1993
2751
|
}
|
|
1994
2752
|
};
|
|
@@ -2001,23 +2759,21 @@ function JobUpload({
|
|
|
2001
2759
|
useInput2((_input, key) => {
|
|
2002
2760
|
if (key.escape && phase === "waiting" && !done.current) {
|
|
2003
2761
|
done.current = true;
|
|
2004
|
-
finish.current.onError(
|
|
2005
|
-
"annul\xE9 avant le d\xE9but de l\u2019upload \u2014 le job sera coup\xE9 automatiquement c\xF4t\xE9 serveur (quota rembours\xE9)."
|
|
2006
|
-
);
|
|
2762
|
+
finish.current.onError(t("upload.cancelledBeforeStart"));
|
|
2007
2763
|
}
|
|
2008
2764
|
});
|
|
2009
2765
|
const remaining = Math.max(0, totalBytes - podBytes);
|
|
2010
2766
|
const effectiveRate = podRate > 0 ? podRate : localRate;
|
|
2011
2767
|
return /* @__PURE__ */ jsxs10(Box9, { flexDirection: "column", children: [
|
|
2012
|
-
/* @__PURE__ */ jsx11(Box9, { marginBottom: 1, children: /* @__PURE__ */ jsx11(Text11, { color: COLORS.zinc100, bold: true, children: "
|
|
2768
|
+
/* @__PURE__ */ jsx11(Box9, { marginBottom: 1, children: /* @__PURE__ */ jsx11(Text11, { color: COLORS.zinc100, bold: true, children: t("upload.title") }) }),
|
|
2013
2769
|
/* @__PURE__ */ jsxs10(Text11, { color: COLORS.zinc500, children: [
|
|
2014
2770
|
fileName,
|
|
2015
2771
|
" \xB7 ",
|
|
2016
2772
|
formatBytes(totalBytes)
|
|
2017
2773
|
] }),
|
|
2018
2774
|
phase === "waiting" ? /* @__PURE__ */ jsxs10(Box9, { marginTop: 1, flexDirection: "column", children: [
|
|
2019
|
-
/* @__PURE__ */ jsx11(BusyIndicator, { label: "
|
|
2020
|
-
/* @__PURE__ */ jsx11(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx11(Keycaps, { items: [{ key: "esc", desc: "
|
|
2775
|
+
/* @__PURE__ */ jsx11(BusyIndicator, { label: t("upload.waiting") }),
|
|
2776
|
+
/* @__PURE__ */ jsx11(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx11(Keycaps, { items: [{ key: "esc", desc: t("keycaps.cancel") }] }) })
|
|
2021
2777
|
] }) : /* @__PURE__ */ jsxs10(Box9, { marginTop: 1, flexDirection: "column", children: [
|
|
2022
2778
|
/* @__PURE__ */ jsx11(
|
|
2023
2779
|
ProgressBar,
|
|
@@ -2029,24 +2785,23 @@ function JobUpload({
|
|
|
2029
2785
|
),
|
|
2030
2786
|
/* @__PURE__ */ jsxs10(Box9, { marginTop: 1, flexDirection: "column", children: [
|
|
2031
2787
|
/* @__PURE__ */ jsxs10(Text11, { children: [
|
|
2032
|
-
/* @__PURE__ */ jsx11(Text11, { color: COLORS.zinc500, children: "
|
|
2788
|
+
/* @__PURE__ */ jsx11(Text11, { color: COLORS.zinc500, children: t("upload.localRate") }),
|
|
2033
2789
|
/* @__PURE__ */ jsx11(Text11, { color: COLORS.zinc100, children: formatRate(localRate) }),
|
|
2034
2790
|
/* @__PURE__ */ jsxs10(Text11, { color: COLORS.zinc600, children: [
|
|
2035
|
-
"
|
|
2036
|
-
formatBytes(sentBytes)
|
|
2037
|
-
" envoy\xE9s)"
|
|
2791
|
+
" ",
|
|
2792
|
+
t("upload.bytesSent", { bytes: formatBytes(sentBytes) })
|
|
2038
2793
|
] })
|
|
2039
2794
|
] }),
|
|
2040
2795
|
/* @__PURE__ */ jsxs10(Text11, { children: [
|
|
2041
|
-
/* @__PURE__ */ jsx11(Text11, { color: COLORS.zinc500, children: "
|
|
2796
|
+
/* @__PURE__ */ jsx11(Text11, { color: COLORS.zinc500, children: t("upload.envRate") }),
|
|
2042
2797
|
/* @__PURE__ */ jsx11(Text11, { color: COLORS.zinc100, children: formatRate(podRate) })
|
|
2043
2798
|
] }),
|
|
2044
2799
|
/* @__PURE__ */ jsxs10(Text11, { children: [
|
|
2045
|
-
/* @__PURE__ */ jsx11(Text11, { color: COLORS.zinc500, children: "
|
|
2800
|
+
/* @__PURE__ */ jsx11(Text11, { color: COLORS.zinc500, children: t("upload.etaLabel") }),
|
|
2046
2801
|
/* @__PURE__ */ jsx11(Text11, { color: COLORS.emerald, children: formatEta(remaining, effectiveRate) })
|
|
2047
2802
|
] })
|
|
2048
2803
|
] }),
|
|
2049
|
-
phase === "finalizing" ? /* @__PURE__ */ jsx11(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx11(BusyIndicator, { label: "
|
|
2804
|
+
phase === "finalizing" ? /* @__PURE__ */ jsx11(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx11(BusyIndicator, { label: t("upload.verifying"), compact: true }) }) : /* @__PURE__ */ jsx11(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx11(Text11, { color: COLORS.amber, children: t("upload.warnKeepAlive") }) })
|
|
2050
2805
|
] })
|
|
2051
2806
|
] });
|
|
2052
2807
|
}
|
|
@@ -2471,7 +3226,7 @@ async function runLoginFlow(opts = {}) {
|
|
|
2471
3226
|
const code = await new Promise((resolve3, reject) => {
|
|
2472
3227
|
const timer = setTimeout(
|
|
2473
3228
|
() => reject(
|
|
2474
|
-
new Error(
|
|
3229
|
+
new Error(t("login.err.noBrowserResponse", { min: Math.round(timeoutMs / 6e4) || 1 }))
|
|
2475
3230
|
),
|
|
2476
3231
|
timeoutMs
|
|
2477
3232
|
);
|
|
@@ -2482,18 +3237,18 @@ async function runLoginFlow(opts = {}) {
|
|
|
2482
3237
|
return;
|
|
2483
3238
|
}
|
|
2484
3239
|
const fail = (msg) => {
|
|
2485
|
-
res.writeHead(400, { "content-type": "text/html; charset=utf-8" }).end(page("
|
|
3240
|
+
res.writeHead(400, { "content-type": "text/html; charset=utf-8" }).end(page(t("login.failedTitle"), msg, false));
|
|
2486
3241
|
clearTimeout(timer);
|
|
2487
3242
|
reject(new Error(msg));
|
|
2488
3243
|
};
|
|
2489
3244
|
const err = url.searchParams.get("error");
|
|
2490
|
-
if (err) return fail(
|
|
3245
|
+
if (err) return fail(t("login.err.serverRefused", { error: err }));
|
|
2491
3246
|
if (url.searchParams.get("state") !== state) {
|
|
2492
|
-
return fail(
|
|
3247
|
+
return fail(t("login.err.invalidState"));
|
|
2493
3248
|
}
|
|
2494
3249
|
const code2 = url.searchParams.get("code");
|
|
2495
|
-
if (!code2) return fail("
|
|
2496
|
-
res.writeHead(200, { "content-type": "text/html; charset=utf-8" }).end(page("
|
|
3250
|
+
if (!code2) return fail(t("login.err.missingCode"));
|
|
3251
|
+
res.writeHead(200, { "content-type": "text/html; charset=utf-8" }).end(page(t("login.connectedTitle"), t("login.connectedBody"), true));
|
|
2497
3252
|
clearTimeout(timer);
|
|
2498
3253
|
resolve3(code2);
|
|
2499
3254
|
});
|
|
@@ -2593,15 +3348,15 @@ function KeyValue({ rows }) {
|
|
|
2593
3348
|
// src/ui/JobSummary.tsx
|
|
2594
3349
|
import { jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
2595
3350
|
var STATUS_LABEL2 = {
|
|
2596
|
-
created: "
|
|
2597
|
-
provisioning: "
|
|
2598
|
-
starting: "
|
|
2599
|
-
bootstrapping: "
|
|
2600
|
-
running: "
|
|
2601
|
-
terminating: "
|
|
2602
|
-
succeeded: "
|
|
2603
|
-
failed: "
|
|
2604
|
-
cancelled: "
|
|
3351
|
+
created: t("watch.status.created"),
|
|
3352
|
+
provisioning: t("watch.status.provisioning"),
|
|
3353
|
+
starting: t("watch.status.starting"),
|
|
3354
|
+
bootstrapping: t("watch.status.bootstrapping"),
|
|
3355
|
+
running: t("watch.status.running"),
|
|
3356
|
+
terminating: t("watch.status.terminating"),
|
|
3357
|
+
succeeded: t("watch.status.succeeded"),
|
|
3358
|
+
failed: t("watch.status.failed"),
|
|
3359
|
+
cancelled: t("watch.status.cancelled")
|
|
2605
3360
|
};
|
|
2606
3361
|
var STATUS_COLOR = {
|
|
2607
3362
|
succeeded: COLORS.emerald,
|
|
@@ -2611,8 +3366,8 @@ var STATUS_COLOR = {
|
|
|
2611
3366
|
var fmtCost = (n) => n != null ? `${n.toFixed(4)} $` : "\u2014";
|
|
2612
3367
|
var parseIso = (iso) => {
|
|
2613
3368
|
if (!iso) return null;
|
|
2614
|
-
const
|
|
2615
|
-
return Number.isFinite(
|
|
3369
|
+
const t2 = new Date(iso).getTime();
|
|
3370
|
+
return Number.isFinite(t2) ? t2 : null;
|
|
2616
3371
|
};
|
|
2617
3372
|
var fmtDuration2 = (b) => {
|
|
2618
3373
|
const start = parseIso(b.created_at);
|
|
@@ -2626,29 +3381,29 @@ function JobSummary({ build }) {
|
|
|
2626
3381
|
const color = STATUS_COLOR[build.status] ?? COLORS.zinc400;
|
|
2627
3382
|
const totalCost = (build.cost_runpod_usd ?? 0) + (build.cost_deepseek_usd ?? 0);
|
|
2628
3383
|
const rows = [
|
|
2629
|
-
["
|
|
2630
|
-
["type", build.kind === "simulation" ? "simulation" : "build"]
|
|
3384
|
+
[t("jobSummary.row.status"), STATUS_LABEL2[build.status] ?? build.status],
|
|
3385
|
+
[t("jobSummary.row.type"), build.kind === "simulation" ? t("jobSummary.type.simulation") : t("jobSummary.type.build")]
|
|
2631
3386
|
];
|
|
2632
3387
|
if (build.kind === "simulation" && build.simulation_task) {
|
|
2633
3388
|
const task = build.simulation_task;
|
|
2634
|
-
rows.push([
|
|
3389
|
+
rows.push([t("jobSummary.row.task"), task.length > 80 ? task.slice(0, 77) + "\u2026" : task]);
|
|
2635
3390
|
}
|
|
2636
3391
|
if (build.weights_artifact_id) {
|
|
2637
|
-
rows.push(["
|
|
3392
|
+
rows.push([t("jobSummary.row.weights"), build.weights_artifact_id.slice(0, 8)]);
|
|
2638
3393
|
}
|
|
2639
3394
|
rows.push(
|
|
2640
|
-
["
|
|
2641
|
-
["
|
|
2642
|
-
["
|
|
2643
|
-
["
|
|
2644
|
-
["
|
|
3395
|
+
[t("jobSummary.row.duration"), fmtDuration2(build)],
|
|
3396
|
+
[t("jobSummary.row.environment"), build.pod?.machine ?? "\u2014"],
|
|
3397
|
+
[t("jobSummary.row.costEnv"), fmtCost(build.cost_runpod_usd)],
|
|
3398
|
+
[t("jobSummary.row.costAgent"), `${fmtCost(build.cost_deepseek_usd)} \xB7 ${build.agent_calls ?? 0} appel(s)`],
|
|
3399
|
+
[t("jobSummary.row.costTotal"), fmtCost(totalCost)]
|
|
2645
3400
|
);
|
|
2646
3401
|
if (build.error) {
|
|
2647
|
-
rows.push(["
|
|
3402
|
+
rows.push([t("jobSummary.row.error"), build.error.length > 80 ? build.error.slice(0, 77) + "\u2026" : build.error]);
|
|
2648
3403
|
}
|
|
2649
3404
|
return /* @__PURE__ */ jsxs13(Box12, { flexDirection: "column", children: [
|
|
2650
3405
|
/* @__PURE__ */ jsxs13(Text14, { color, bold: true, children: [
|
|
2651
|
-
build.kind === "simulation" ? "simulation" : "build",
|
|
3406
|
+
build.kind === "simulation" ? t("jobSummary.type.simulation") : t("jobSummary.type.build"),
|
|
2652
3407
|
" ",
|
|
2653
3408
|
build.id.slice(0, 8)
|
|
2654
3409
|
] }),
|
|
@@ -2665,12 +3420,16 @@ function SelectList({
|
|
|
2665
3420
|
onSelect,
|
|
2666
3421
|
isActive = true,
|
|
2667
3422
|
initialIndex = 0,
|
|
2668
|
-
showHint = true
|
|
3423
|
+
showHint = true,
|
|
3424
|
+
onIndexChange
|
|
2669
3425
|
}) {
|
|
2670
3426
|
const [index, setIndex] = useState4(initialIndex);
|
|
2671
3427
|
useEffect4(() => {
|
|
2672
3428
|
if (index >= items.length) setIndex(Math.max(0, items.length - 1));
|
|
2673
3429
|
}, [items.length, index]);
|
|
3430
|
+
useEffect4(() => {
|
|
3431
|
+
onIndexChange?.(index);
|
|
3432
|
+
}, [index]);
|
|
2674
3433
|
useInput3(
|
|
2675
3434
|
(input, key) => {
|
|
2676
3435
|
if (key.upArrow || input === "k") {
|
|
@@ -2707,7 +3466,7 @@ function SelectList({
|
|
|
2707
3466
|
] }) : null
|
|
2708
3467
|
] }, item.value);
|
|
2709
3468
|
}),
|
|
2710
|
-
showHint && isActive ? /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(Text15, { color: COLORS.zinc700, dimColor: true, children: "
|
|
3469
|
+
showHint && isActive ? /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(Text15, { color: COLORS.zinc700, dimColor: true, children: t("selectList.hint") }) }) : null
|
|
2711
3470
|
] });
|
|
2712
3471
|
}
|
|
2713
3472
|
|
|
@@ -2907,12 +3666,12 @@ function semverCmp(a, b) {
|
|
|
2907
3666
|
async function fetchLatest() {
|
|
2908
3667
|
try {
|
|
2909
3668
|
const ctrl = new AbortController();
|
|
2910
|
-
const
|
|
3669
|
+
const t2 = setTimeout(() => ctrl.abort(), CHECK_TIMEOUT_MS);
|
|
2911
3670
|
const res = await fetch(`${labUrl()}/cli/latest`, {
|
|
2912
3671
|
signal: ctrl.signal,
|
|
2913
3672
|
headers: { "x-cli-version": CLI_VERSION }
|
|
2914
3673
|
});
|
|
2915
|
-
clearTimeout(
|
|
3674
|
+
clearTimeout(t2);
|
|
2916
3675
|
if (!res.ok) return null;
|
|
2917
3676
|
const j = await res.json();
|
|
2918
3677
|
if (!j.version || !j.tarball_url || !j.signature || !j.sha256) return null;
|
|
@@ -3008,7 +3767,7 @@ function installTarball(tarPath, opts = {}) {
|
|
|
3008
3767
|
const r = spawnSync("tar", ["-xzf", tarPath, "-C", staging], { stdio: "ignore" });
|
|
3009
3768
|
if (r.status !== 0) {
|
|
3010
3769
|
rmSync2(staging, { recursive: true, force: true });
|
|
3011
|
-
throw new Error("
|
|
3770
|
+
throw new Error(t("update.err.extractFailed"));
|
|
3012
3771
|
}
|
|
3013
3772
|
const newDist = join4(staging, "dist");
|
|
3014
3773
|
if (!existsSync(join4(newDist, "main.js"))) {
|
|
@@ -3063,9 +3822,9 @@ function realNorm(p) {
|
|
|
3063
3822
|
}
|
|
3064
3823
|
}
|
|
3065
3824
|
function isDangerousRoot(root) {
|
|
3066
|
-
const
|
|
3067
|
-
if (
|
|
3068
|
-
const n = norm(
|
|
3825
|
+
const t2 = root.trim();
|
|
3826
|
+
if (t2 === "") return true;
|
|
3827
|
+
const n = norm(t2);
|
|
3069
3828
|
if (n === sep) return true;
|
|
3070
3829
|
if (n === norm(homedir2())) return true;
|
|
3071
3830
|
return false;
|
|
@@ -3221,7 +3980,7 @@ function scheduleInstallRemoval(plan, opts = {}) {
|
|
|
3221
3980
|
return {
|
|
3222
3981
|
step: "install",
|
|
3223
3982
|
ok: false,
|
|
3224
|
-
error:
|
|
3983
|
+
error: t("uninstall.scheduleFailed", { err: errMsg(e), manual: plan.manualHint ?? plan.installRoot })
|
|
3225
3984
|
};
|
|
3226
3985
|
}
|
|
3227
3986
|
}
|
|
@@ -3247,20 +4006,22 @@ async function performUninstall(plan) {
|
|
|
3247
4006
|
// src/ui/UninstallScreen.tsx
|
|
3248
4007
|
import { jsx as jsx17, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
3249
4008
|
function channelLabel(c) {
|
|
3250
|
-
return c === "npm" ? "npm
|
|
4009
|
+
return c === "npm" ? t("uninstall.channel.npm") : c === "selfhosted" ? t("uninstall.channel.selfhosted") : t("uninstall.channel.binary");
|
|
3251
4010
|
}
|
|
3252
4011
|
function planRows(plan) {
|
|
3253
|
-
const rows = [["
|
|
4012
|
+
const rows = [[t("uninstall.row.channel"), channelLabel(plan.channel)]];
|
|
4013
|
+
const install = t("uninstall.row.install");
|
|
3254
4014
|
if (plan.channel === "npm") {
|
|
3255
|
-
rows.push(["install",
|
|
4015
|
+
rows.push([install, t("uninstall.install.atClose", { root: plan.manualHint ?? "npm" })]);
|
|
3256
4016
|
} else if (plan.installBlockedReason) {
|
|
3257
|
-
rows.push(["install",
|
|
4017
|
+
rows.push([install, t("uninstall.install.manual", { hint: plan.manualHint ?? plan.installRoot })]);
|
|
3258
4018
|
} else {
|
|
3259
|
-
rows.push(["install",
|
|
3260
|
-
if (plan.launcherPath)
|
|
4019
|
+
rows.push([install, t("uninstall.install.atClose", { root: plan.installRoot })]);
|
|
4020
|
+
if (plan.launcherPath)
|
|
4021
|
+
rows.push(["launcher", t("uninstall.install.atClose", { root: plan.launcherPath })]);
|
|
3261
4022
|
}
|
|
3262
|
-
rows.push(["config",
|
|
3263
|
-
rows.push(["credentials", "
|
|
4023
|
+
rows.push([t("uninstall.row.config"), t("uninstall.config.now", { configDir: plan.configDir })]);
|
|
4024
|
+
rows.push([t("uninstall.row.credentials"), t("uninstall.credentials.keychainFileNow")]);
|
|
3264
4025
|
return rows;
|
|
3265
4026
|
}
|
|
3266
4027
|
function UninstallView({
|
|
@@ -3277,13 +4038,13 @@ function UninstallView({
|
|
|
3277
4038
|
if (view.kind === "working") {
|
|
3278
4039
|
return /* @__PURE__ */ jsx17(Box15, { flexDirection: "column", children: /* @__PURE__ */ jsxs16(Text17, { color: COLORS.zinc400, children: [
|
|
3279
4040
|
/* @__PURE__ */ jsx17(Text17, { color: COLORS.emerald, children: "\xB7 " }),
|
|
3280
|
-
"
|
|
4041
|
+
t("uninstall.working")
|
|
3281
4042
|
] }) });
|
|
3282
4043
|
}
|
|
3283
4044
|
if (view.kind === "report") {
|
|
3284
4045
|
const dataFailed = view.report.some((s) => s.step !== "install" && !s.ok);
|
|
3285
4046
|
return /* @__PURE__ */ jsxs16(Box15, { flexDirection: "column", children: [
|
|
3286
|
-
/* @__PURE__ */ jsx17(Text17, { color: COLORS.zinc100, bold: true, children: "
|
|
4047
|
+
/* @__PURE__ */ jsx17(Text17, { color: COLORS.zinc100, bold: true, children: t("uninstall.report.title") }),
|
|
3287
4048
|
/* @__PURE__ */ jsx17(Box15, { flexDirection: "column", marginTop: 1, children: view.report.map((s) => /* @__PURE__ */ jsxs16(Box15, { children: [
|
|
3288
4049
|
/* @__PURE__ */ jsx17(Text17, { color: s.ok ? COLORS.emerald : COLORS.red, children: s.ok ? "\u2713 " : "\u2717 " }),
|
|
3289
4050
|
/* @__PURE__ */ jsx17(Text17, { color: COLORS.zinc300, children: s.step }),
|
|
@@ -3292,26 +4053,26 @@ function UninstallView({
|
|
|
3292
4053
|
s.error
|
|
3293
4054
|
] }) : null
|
|
3294
4055
|
] }, s.step)) }),
|
|
3295
|
-
/* @__PURE__ */ jsx17(Box15, { marginTop: 1, flexDirection: "column", children: !dataFailed ? /* @__PURE__ */ jsx17(Text17, { color: COLORS.zinc400, children: "
|
|
4056
|
+
/* @__PURE__ */ jsx17(Box15, { marginTop: 1, flexDirection: "column", children: !dataFailed ? /* @__PURE__ */ jsx17(Text17, { color: COLORS.zinc400, children: t("uninstall.report.done") }) : /* @__PURE__ */ jsx17(Text17, { color: COLORS.amber, children: t("uninstall.report.someFailed") }) }),
|
|
3296
4057
|
/* @__PURE__ */ jsx17(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx17(
|
|
3297
4058
|
SelectList,
|
|
3298
4059
|
{
|
|
3299
|
-
items: [{ label: "
|
|
4060
|
+
items: [{ label: t("uninstall.close"), value: "close" }],
|
|
3300
4061
|
onSelect: () => onDone(view.report)
|
|
3301
4062
|
}
|
|
3302
4063
|
) })
|
|
3303
4064
|
] });
|
|
3304
4065
|
}
|
|
3305
4066
|
return /* @__PURE__ */ jsxs16(Box15, { flexDirection: "column", children: [
|
|
3306
|
-
/* @__PURE__ */ jsx17(Text17, { color: COLORS.zinc100, bold: true, children: "
|
|
3307
|
-
/* @__PURE__ */ jsx17(Box15, { marginTop: 1, marginBottom: 1, children: /* @__PURE__ */ jsx17(Text17, { color: COLORS.zinc500, children: "
|
|
4067
|
+
/* @__PURE__ */ jsx17(Text17, { color: COLORS.zinc100, bold: true, children: t("uninstall.confirm.title") }),
|
|
4068
|
+
/* @__PURE__ */ jsx17(Box15, { marginTop: 1, marginBottom: 1, children: /* @__PURE__ */ jsx17(Text17, { color: COLORS.zinc500, children: t("uninstall.confirm.warning") }) }),
|
|
3308
4069
|
/* @__PURE__ */ jsx17(KeyValue, { rows: planRows(plan) }),
|
|
3309
4070
|
/* @__PURE__ */ jsx17(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx17(
|
|
3310
4071
|
SelectList,
|
|
3311
4072
|
{
|
|
3312
4073
|
items: [
|
|
3313
|
-
{ label: "
|
|
3314
|
-
{ label: "
|
|
4074
|
+
{ label: t("uninstall.cancel"), value: "cancel", hint: t("uninstall.cancel.hint") },
|
|
4075
|
+
{ label: t("uninstall.confirmDelete"), value: "go", labelColor: COLORS.red }
|
|
3315
4076
|
],
|
|
3316
4077
|
onSelect: (i) => {
|
|
3317
4078
|
if (i.value === "go") void run();
|
|
@@ -3355,8 +4116,8 @@ var FRAME_MS2 = 120;
|
|
|
3355
4116
|
function Twinkle({ color = COLORS.emerald }) {
|
|
3356
4117
|
const [frame, setFrame] = useState7(0);
|
|
3357
4118
|
useEffect5(() => {
|
|
3358
|
-
const
|
|
3359
|
-
return () => clearInterval(
|
|
4119
|
+
const t2 = setInterval(() => setFrame((f) => (f + 1) % TWINKLE_CYCLE2.length), FRAME_MS2);
|
|
4120
|
+
return () => clearInterval(t2);
|
|
3360
4121
|
}, []);
|
|
3361
4122
|
return /* @__PURE__ */ jsx18(Text18, { color, children: TWINKLE_CYCLE2[frame] });
|
|
3362
4123
|
}
|
|
@@ -3428,15 +4189,15 @@ function NoOrgPage({
|
|
|
3428
4189
|
onQuit
|
|
3429
4190
|
}) {
|
|
3430
4191
|
return /* @__PURE__ */ jsxs17(Box16, { flexDirection: "column", children: [
|
|
3431
|
-
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc100, children: "
|
|
3432
|
-
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc500, children: "
|
|
4192
|
+
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc100, children: t("noOrg.none") }),
|
|
4193
|
+
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc500, children: t("noOrg.createThenReturn") }),
|
|
3433
4194
|
/* @__PURE__ */ jsx19(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx19(
|
|
3434
4195
|
SelectList,
|
|
3435
4196
|
{
|
|
3436
4197
|
items: [
|
|
3437
|
-
{ label: "
|
|
3438
|
-
{ label: "
|
|
3439
|
-
{ label: "
|
|
4198
|
+
{ label: t("noOrg.retry"), value: "retry", hint: t("noOrg.retry.hint") },
|
|
4199
|
+
{ label: t("noOrg.continue"), value: "continue" },
|
|
4200
|
+
{ label: t("common.quit"), value: "quit" }
|
|
3440
4201
|
],
|
|
3441
4202
|
onSelect: (i) => {
|
|
3442
4203
|
if (i.value === "retry") onRetry();
|
|
@@ -3456,6 +4217,12 @@ function App({
|
|
|
3456
4217
|
const { exit } = useApp3();
|
|
3457
4218
|
const { columns, rows } = useTerminalSize();
|
|
3458
4219
|
const [session, setSession] = useState9(initialSession);
|
|
4220
|
+
const [locale, setLocaleState] = useState9(getLocale());
|
|
4221
|
+
const switchLocale = (l) => {
|
|
4222
|
+
setLocale(l);
|
|
4223
|
+
setLocaleState(l);
|
|
4224
|
+
};
|
|
4225
|
+
void locale;
|
|
3459
4226
|
const [page2, setPageState] = useState9(
|
|
3460
4227
|
initialSession ? { name: "home" } : { name: "landing" }
|
|
3461
4228
|
);
|
|
@@ -3484,10 +4251,10 @@ function App({
|
|
|
3484
4251
|
setPageState(p);
|
|
3485
4252
|
};
|
|
3486
4253
|
const back = () => setPage(parentOf(page2));
|
|
3487
|
-
const backItem = (label = "
|
|
4254
|
+
const backItem = (label = t("common.back")) => ({
|
|
3488
4255
|
label,
|
|
3489
4256
|
value: "__back__",
|
|
3490
|
-
hint: "
|
|
4257
|
+
hint: t("common.orEscape")
|
|
3491
4258
|
});
|
|
3492
4259
|
const [recentBuilds, setRecentBuilds] = useState9(null);
|
|
3493
4260
|
const [recentError, setRecentError] = useState9(null);
|
|
@@ -3501,6 +4268,17 @@ function App({
|
|
|
3501
4268
|
},
|
|
3502
4269
|
{ isActive: page2.name === "home" }
|
|
3503
4270
|
);
|
|
4271
|
+
const [homeMenuIndex, setHomeMenuIndex] = useState9(0);
|
|
4272
|
+
const homeLangIndexRef = useRef4(0);
|
|
4273
|
+
useInput5(
|
|
4274
|
+
(_input, key) => {
|
|
4275
|
+
if (!key.leftArrow && !key.rightArrow) return;
|
|
4276
|
+
if (homeFocus !== "menu") return;
|
|
4277
|
+
if (homeMenuIndex !== homeLangIndexRef.current) return;
|
|
4278
|
+
switchLocale(getLocale() === "fr" ? "en" : "fr");
|
|
4279
|
+
},
|
|
4280
|
+
{ isActive: page2.name === "home" }
|
|
4281
|
+
);
|
|
3504
4282
|
const ESCAPE_OWNED = /* @__PURE__ */ new Set([
|
|
3505
4283
|
"home",
|
|
3506
4284
|
"landing",
|
|
@@ -3557,7 +4335,7 @@ function App({
|
|
|
3557
4335
|
};
|
|
3558
4336
|
}, [page2.name]);
|
|
3559
4337
|
const startSimulation = async (task) => {
|
|
3560
|
-
setPage({ name: "loading", label: "
|
|
4338
|
+
setPage({ name: "loading", label: t("simulate.creating") });
|
|
3561
4339
|
try {
|
|
3562
4340
|
const active = await resolveActiveOrg();
|
|
3563
4341
|
if (!active) {
|
|
@@ -3567,7 +4345,7 @@ function App({
|
|
|
3567
4345
|
const buildId = await createSimulation(active.slug, task);
|
|
3568
4346
|
setPage({ name: "watch", buildId });
|
|
3569
4347
|
} catch (e) {
|
|
3570
|
-
toError(e, "
|
|
4348
|
+
toError(e, t("simulate.impossible"), { name: "home" });
|
|
3571
4349
|
}
|
|
3572
4350
|
};
|
|
3573
4351
|
const hfErrorPage = (e) => {
|
|
@@ -3577,38 +4355,38 @@ function App({
|
|
|
3577
4355
|
case "no_token":
|
|
3578
4356
|
return {
|
|
3579
4357
|
name: "error",
|
|
3580
|
-
title: "
|
|
3581
|
-
detail: "
|
|
4358
|
+
title: t("job.hf.err.noToken.title"),
|
|
4359
|
+
detail: t("job.hf.err.noToken.detail"),
|
|
3582
4360
|
back: back2
|
|
3583
4361
|
};
|
|
3584
4362
|
case "invalid_token":
|
|
3585
4363
|
return {
|
|
3586
4364
|
name: "error",
|
|
3587
|
-
title: "
|
|
3588
|
-
detail: "
|
|
4365
|
+
title: t("job.hf.err.invalidToken.title"),
|
|
4366
|
+
detail: t("job.hf.err.invalidToken.detail"),
|
|
3589
4367
|
back: back2
|
|
3590
4368
|
};
|
|
3591
4369
|
case "gated_or_forbidden":
|
|
3592
4370
|
return {
|
|
3593
4371
|
name: "error",
|
|
3594
|
-
title: "
|
|
3595
|
-
detail: "
|
|
4372
|
+
title: t("job.hf.err.gated.title"),
|
|
4373
|
+
detail: t("job.hf.err.gated.detail"),
|
|
3596
4374
|
back: back2
|
|
3597
4375
|
};
|
|
3598
4376
|
case "not_found":
|
|
3599
4377
|
return {
|
|
3600
4378
|
name: "error",
|
|
3601
|
-
title: "
|
|
3602
|
-
detail: "
|
|
4379
|
+
title: t("job.hf.err.notFound.title"),
|
|
4380
|
+
detail: t("job.hf.err.notFound.detail"),
|
|
3603
4381
|
back: back2
|
|
3604
4382
|
};
|
|
3605
4383
|
default:
|
|
3606
|
-
return { name: "error", title: "
|
|
4384
|
+
return { name: "error", title: t("job.hf.err.checkFailed.title"), detail: e.message, back: back2 };
|
|
3607
4385
|
}
|
|
3608
4386
|
}
|
|
3609
4387
|
return {
|
|
3610
4388
|
name: "error",
|
|
3611
|
-
title: "
|
|
4389
|
+
title: t("job.hf.err.checkFailed.title"),
|
|
3612
4390
|
detail: e instanceof Error ? e.message : String(e),
|
|
3613
4391
|
back: back2
|
|
3614
4392
|
};
|
|
@@ -3618,13 +4396,13 @@ function App({
|
|
|
3618
4396
|
if (!parsed) {
|
|
3619
4397
|
setPage({
|
|
3620
4398
|
name: "error",
|
|
3621
|
-
title: "
|
|
3622
|
-
detail: "
|
|
4399
|
+
title: t("job.hf.invalidRef.title"),
|
|
4400
|
+
detail: t("job.hf.invalidRef.detail"),
|
|
3623
4401
|
back: { name: "job-hf" }
|
|
3624
4402
|
});
|
|
3625
4403
|
return;
|
|
3626
4404
|
}
|
|
3627
|
-
setPage({ name: "loading", label: "
|
|
4405
|
+
setPage({ name: "loading", label: t("job.hf.checking") });
|
|
3628
4406
|
try {
|
|
3629
4407
|
const active = await resolveActiveOrg();
|
|
3630
4408
|
if (!active) {
|
|
@@ -3644,7 +4422,7 @@ function App({
|
|
|
3644
4422
|
}
|
|
3645
4423
|
};
|
|
3646
4424
|
const startHfJob = async (repo, revision) => {
|
|
3647
|
-
setPage({ name: "loading", label: "
|
|
4425
|
+
setPage({ name: "loading", label: t("common.creatingJob") });
|
|
3648
4426
|
try {
|
|
3649
4427
|
const active = await resolveActiveOrg();
|
|
3650
4428
|
if (!active) {
|
|
@@ -3657,7 +4435,7 @@ function App({
|
|
|
3657
4435
|
if (e instanceof ApiError && ["no_token", "invalid_token", "gated_or_forbidden", "not_found"].includes(e.code)) {
|
|
3658
4436
|
setPage(hfErrorPage(e));
|
|
3659
4437
|
} else {
|
|
3660
|
-
toError(e, "
|
|
4438
|
+
toError(e, t("common.jobImpossible"), { name: "home" });
|
|
3661
4439
|
}
|
|
3662
4440
|
}
|
|
3663
4441
|
};
|
|
@@ -3677,8 +4455,8 @@ function App({
|
|
|
3677
4455
|
if (!st.isFile()) {
|
|
3678
4456
|
setPage({
|
|
3679
4457
|
name: "error",
|
|
3680
|
-
title: "
|
|
3681
|
-
detail:
|
|
4458
|
+
title: t("job.file.err.notFile.title"),
|
|
4459
|
+
detail: t("job.file.err.notFile.detail", { path: p }),
|
|
3682
4460
|
back: { name: "job-file" }
|
|
3683
4461
|
});
|
|
3684
4462
|
return;
|
|
@@ -3687,7 +4465,7 @@ function App({
|
|
|
3687
4465
|
} catch {
|
|
3688
4466
|
setPage({
|
|
3689
4467
|
name: "error",
|
|
3690
|
-
title: "
|
|
4468
|
+
title: t("job.file.err.notFound.title"),
|
|
3691
4469
|
detail: p,
|
|
3692
4470
|
back: { name: "job-file" }
|
|
3693
4471
|
});
|
|
@@ -3696,7 +4474,7 @@ function App({
|
|
|
3696
4474
|
if (size <= 0) {
|
|
3697
4475
|
setPage({
|
|
3698
4476
|
name: "error",
|
|
3699
|
-
title: "
|
|
4477
|
+
title: t("job.file.err.empty.title"),
|
|
3700
4478
|
detail: p,
|
|
3701
4479
|
back: { name: "job-file" }
|
|
3702
4480
|
});
|
|
@@ -3705,7 +4483,7 @@ function App({
|
|
|
3705
4483
|
setPage({ name: "job-file-confirm", filePath: p, fileName: path.basename(p), sizeBytes: size });
|
|
3706
4484
|
};
|
|
3707
4485
|
const startDirectJob = async (filePath2, fileName, sizeBytes) => {
|
|
3708
|
-
setPage({ name: "loading", label: "
|
|
4486
|
+
setPage({ name: "loading", label: t("common.creatingJob") });
|
|
3709
4487
|
try {
|
|
3710
4488
|
const active = await resolveActiveOrg();
|
|
3711
4489
|
if (!active) {
|
|
@@ -3719,8 +4497,8 @@ function App({
|
|
|
3719
4497
|
});
|
|
3720
4498
|
if (!created.upload_token) {
|
|
3721
4499
|
toError(
|
|
3722
|
-
new Error("
|
|
3723
|
-
"
|
|
4500
|
+
new Error(t("job.noUploadToken")),
|
|
4501
|
+
t("common.jobImpossible"),
|
|
3724
4502
|
{ name: "home" }
|
|
3725
4503
|
);
|
|
3726
4504
|
return;
|
|
@@ -3734,11 +4512,11 @@ function App({
|
|
|
3734
4512
|
sizeBytes
|
|
3735
4513
|
});
|
|
3736
4514
|
} catch (e) {
|
|
3737
|
-
toError(e, "
|
|
4515
|
+
toError(e, t("common.jobImpossible"), { name: "home" });
|
|
3738
4516
|
}
|
|
3739
4517
|
};
|
|
3740
4518
|
const openBuildSummary = async (buildId, opts = {}) => {
|
|
3741
|
-
if (!opts.quiet) setPage({ name: "loading", label: "
|
|
4519
|
+
if (!opts.quiet) setPage({ name: "loading", label: t("job.fetching") });
|
|
3742
4520
|
try {
|
|
3743
4521
|
const active = await resolveActiveOrg();
|
|
3744
4522
|
if (!active) {
|
|
@@ -3748,18 +4526,18 @@ function App({
|
|
|
3748
4526
|
const build = await getBuild(active.slug, buildId);
|
|
3749
4527
|
setPage({ name: "build-summary", build });
|
|
3750
4528
|
} catch (e) {
|
|
3751
|
-
toError(e, "job
|
|
4529
|
+
toError(e, t("job.notFound"), { name: "home" });
|
|
3752
4530
|
}
|
|
3753
4531
|
};
|
|
3754
4532
|
const loadOrgs = async (back2) => {
|
|
3755
|
-
setPage({ name: "loading", label: "
|
|
4533
|
+
setPage({ name: "loading", label: t("orgs.loading") });
|
|
3756
4534
|
try {
|
|
3757
4535
|
const me = await labApi("/me");
|
|
3758
4536
|
const orgs = await labApi("/orgs");
|
|
3759
4537
|
if (orgs.length === 0) setPage({ name: "no-org" });
|
|
3760
4538
|
else setPage({ name: "orgs", me, orgs });
|
|
3761
4539
|
} catch (e) {
|
|
3762
|
-
toError(e, "
|
|
4540
|
+
toError(e, t("orgs.fetchFailed"), back2);
|
|
3763
4541
|
}
|
|
3764
4542
|
};
|
|
3765
4543
|
const startBrowserLogin = async () => {
|
|
@@ -3774,19 +4552,19 @@ function App({
|
|
|
3774
4552
|
setSession("oauth");
|
|
3775
4553
|
await loadOrgs({ name: "landing" });
|
|
3776
4554
|
} catch (e) {
|
|
3777
|
-
toError(e, "
|
|
4555
|
+
toError(e, t("common.loginFailed"), { name: "landing" });
|
|
3778
4556
|
}
|
|
3779
4557
|
};
|
|
3780
4558
|
const submitKey = async (key) => {
|
|
3781
4559
|
const trimmed = key.trim();
|
|
3782
4560
|
if (!trimmed) return;
|
|
3783
|
-
setPage({ name: "loading", label: "
|
|
4561
|
+
setPage({ name: "loading", label: t("login.validatingKey") });
|
|
3784
4562
|
try {
|
|
3785
4563
|
await saveCredentials({ kind: "api-key", apiKey: trimmed });
|
|
3786
4564
|
await labApi("/me");
|
|
3787
4565
|
} catch (e) {
|
|
3788
4566
|
await clearCredentials();
|
|
3789
|
-
toError(e, "
|
|
4567
|
+
toError(e, t("login.invalidKey"), { name: "login-key" });
|
|
3790
4568
|
return;
|
|
3791
4569
|
}
|
|
3792
4570
|
setSession("api-key");
|
|
@@ -3797,7 +4575,7 @@ function App({
|
|
|
3797
4575
|
setPage({ name: "home" });
|
|
3798
4576
|
};
|
|
3799
4577
|
const showQuota = async () => {
|
|
3800
|
-
setPage({ name: "loading", label: "quota
|
|
4578
|
+
setPage({ name: "loading", label: t("quota.loading") });
|
|
3801
4579
|
try {
|
|
3802
4580
|
const active = await resolveActiveOrg();
|
|
3803
4581
|
if (!active) {
|
|
@@ -3807,20 +4585,20 @@ function App({
|
|
|
3807
4585
|
const q = await getOrgQuota(active.slug);
|
|
3808
4586
|
setPage({ name: "quota", orgName: active.name, remaining: q.remaining });
|
|
3809
4587
|
} catch (e) {
|
|
3810
|
-
toError(e, "quota
|
|
4588
|
+
toError(e, t("quota.unreachable"), { name: "home" });
|
|
3811
4589
|
}
|
|
3812
4590
|
};
|
|
3813
4591
|
const showWhoami = async () => {
|
|
3814
|
-
setPage({ name: "loading", label: "
|
|
4592
|
+
setPage({ name: "loading", label: t("whoami.loading") });
|
|
3815
4593
|
try {
|
|
3816
4594
|
const me = await labApi("/me");
|
|
3817
4595
|
setPage({ name: "whoami", me });
|
|
3818
4596
|
} catch (e) {
|
|
3819
|
-
toError(e, "
|
|
4597
|
+
toError(e, t("whoami.unreachable"), { name: "home" });
|
|
3820
4598
|
}
|
|
3821
4599
|
};
|
|
3822
4600
|
const logout = async () => {
|
|
3823
|
-
setPage({ name: "loading", label: "
|
|
4601
|
+
setPage({ name: "loading", label: t("common.signingOut") });
|
|
3824
4602
|
await clearCredentials();
|
|
3825
4603
|
const cfg = loadConfig();
|
|
3826
4604
|
delete cfg.activeOrgId;
|
|
@@ -3833,14 +4611,14 @@ function App({
|
|
|
3833
4611
|
switch (page2.name) {
|
|
3834
4612
|
case "landing":
|
|
3835
4613
|
body = /* @__PURE__ */ jsxs17(Box16, { flexDirection: "column", children: [
|
|
3836
|
-
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc500, children: "
|
|
4614
|
+
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc500, children: t("landing.howConnect") }),
|
|
3837
4615
|
/* @__PURE__ */ jsx19(
|
|
3838
4616
|
SelectList,
|
|
3839
4617
|
{
|
|
3840
4618
|
items: [
|
|
3841
|
-
{ label: "
|
|
3842
|
-
{ label: "
|
|
3843
|
-
{ label: "
|
|
4619
|
+
{ label: t("landing.menu.browser"), value: "browser", hint: t("landing.menu.browser.hint") },
|
|
4620
|
+
{ label: t("landing.menu.key"), value: "key", hint: t("landing.menu.key.hint") },
|
|
4621
|
+
{ label: t("landing.menu.later"), value: "later", hint: t("landing.menu.later.hint") }
|
|
3844
4622
|
],
|
|
3845
4623
|
onSelect: (i) => {
|
|
3846
4624
|
if (i.value === "browser") void startBrowserLogin();
|
|
@@ -3853,9 +4631,9 @@ function App({
|
|
|
3853
4631
|
break;
|
|
3854
4632
|
case "login-browser":
|
|
3855
4633
|
body = /* @__PURE__ */ jsxs17(Box16, { flexDirection: "column", children: [
|
|
3856
|
-
/* @__PURE__ */ jsx19(BusyIndicator, { label: "
|
|
4634
|
+
/* @__PURE__ */ jsx19(BusyIndicator, { label: t("common.waitingBrowserLogin"), compact: true }),
|
|
3857
4635
|
page2.url ? /* @__PURE__ */ jsxs17(Box16, { marginTop: 1, flexDirection: "column", children: [
|
|
3858
|
-
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc600, children: "
|
|
4636
|
+
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc600, children: t("login.browser.copyUrl") }),
|
|
3859
4637
|
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc400, children: page2.url })
|
|
3860
4638
|
] }) : null
|
|
3861
4639
|
] });
|
|
@@ -3865,13 +4643,13 @@ function App({
|
|
|
3865
4643
|
/* @__PURE__ */ jsx19(
|
|
3866
4644
|
TextField,
|
|
3867
4645
|
{
|
|
3868
|
-
title: "
|
|
3869
|
-
placeholder: "
|
|
4646
|
+
title: t("login.key.title"),
|
|
4647
|
+
placeholder: t("login.key.placeholder"),
|
|
3870
4648
|
onSubmit: (v) => void submitKey(v),
|
|
3871
4649
|
onCancel: () => back()
|
|
3872
4650
|
}
|
|
3873
4651
|
),
|
|
3874
|
-
/* @__PURE__ */ jsx19(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx19(Keycaps, { items: [{ key: "enter", desc: "
|
|
4652
|
+
/* @__PURE__ */ jsx19(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx19(Keycaps, { items: [{ key: "enter", desc: t("keycaps.validate") }, { key: "esc", desc: t("keycaps.back") }] }) })
|
|
3875
4653
|
] });
|
|
3876
4654
|
break;
|
|
3877
4655
|
case "loading":
|
|
@@ -3882,19 +4660,16 @@ function App({
|
|
|
3882
4660
|
break;
|
|
3883
4661
|
case "orgs":
|
|
3884
4662
|
body = /* @__PURE__ */ jsxs17(Box16, { flexDirection: "column", children: [
|
|
3885
|
-
/* @__PURE__ */
|
|
3886
|
-
"connect\xE9 : ",
|
|
3887
|
-
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc100, children: page2.me.email })
|
|
3888
|
-
] }),
|
|
4663
|
+
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc400, children: t("common.connectedAs", { email: page2.me.email }) }),
|
|
3889
4664
|
/* @__PURE__ */ jsxs17(Box16, { marginTop: 1, flexDirection: "column", children: [
|
|
3890
|
-
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc500, children: "
|
|
4665
|
+
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc500, children: t("common.activeOrgLabel") }),
|
|
3891
4666
|
/* @__PURE__ */ jsx19(
|
|
3892
4667
|
SelectList,
|
|
3893
4668
|
{
|
|
3894
4669
|
items: page2.orgs.map((o) => ({
|
|
3895
4670
|
label: o.name,
|
|
3896
4671
|
value: o._id,
|
|
3897
|
-
hint: `${o.slug} \xB7 ${o.members.find((m) => m.user_id === page2.me.id)?.role ?? "member"}`
|
|
4672
|
+
hint: `${o.slug} \xB7 ${o.members.find((m) => m.user_id === page2.me.id)?.role ?? t("orgs.role.member")}`
|
|
3898
4673
|
})),
|
|
3899
4674
|
onSelect: (item) => {
|
|
3900
4675
|
const org2 = page2.orgs.find((o) => o._id === item.value);
|
|
@@ -3917,24 +4692,27 @@ function App({
|
|
|
3917
4692
|
break;
|
|
3918
4693
|
case "home": {
|
|
3919
4694
|
const cfg = loadConfig();
|
|
4695
|
+
const langLabel = `Langue / Language : ${getLocale() === "fr" ? "Fran\xE7ais" : "English"} \u203A`;
|
|
3920
4696
|
const menuItems = [
|
|
3921
|
-
{ label: "
|
|
3922
|
-
{ label: "
|
|
3923
|
-
{ label: "
|
|
3924
|
-
{ label: "
|
|
3925
|
-
{ label: "
|
|
3926
|
-
{ label: "
|
|
3927
|
-
{ label:
|
|
3928
|
-
{ label: "
|
|
3929
|
-
{ label: "
|
|
4697
|
+
{ label: t("home.menu.job"), value: "job", hint: t("home.menu.job.hint") },
|
|
4698
|
+
{ label: t("home.menu.simulate"), value: "simulate", hint: t("home.menu.simulate.hint") },
|
|
4699
|
+
{ label: t("home.menu.quota"), value: "quota", hint: t("home.menu.quota.hint") },
|
|
4700
|
+
{ label: t("home.menu.orgs"), value: "orgs" },
|
|
4701
|
+
{ label: t("home.menu.whoami"), value: "whoami", hint: t("home.menu.whoami.hint") },
|
|
4702
|
+
{ label: t("home.menu.refresh"), value: "refresh" },
|
|
4703
|
+
{ label: langLabel, value: "lang", hint: t("home.menu.lang.hint") },
|
|
4704
|
+
{ label: t("home.menu.logout"), value: "logout" },
|
|
4705
|
+
{ label: t("home.menu.uninstall"), value: "uninstall", hint: t("home.menu.uninstall.hint") },
|
|
4706
|
+
{ label: t("common.quit"), value: "quit" }
|
|
3930
4707
|
];
|
|
4708
|
+
homeLangIndexRef.current = menuItems.findIndex((i) => i.value === "lang");
|
|
3931
4709
|
body = /* @__PURE__ */ jsxs17(Box16, { flexDirection: "column", children: [
|
|
3932
4710
|
/* @__PURE__ */ jsxs17(Box16, { flexDirection: "column", marginBottom: 1, children: [
|
|
3933
4711
|
/* @__PURE__ */ jsx19(Box16, { children: /* @__PURE__ */ jsxs17(Text19, { color: homeFocus === "history" ? COLORS.emerald : COLORS.zinc500, children: [
|
|
3934
4712
|
homeFocus === "history" ? "\u25B8 " : " ",
|
|
3935
|
-
"
|
|
4713
|
+
t("home.recentJobs")
|
|
3936
4714
|
] }) }),
|
|
3937
|
-
recentBuilds === null ? /* @__PURE__ */ jsx19(Box16, { marginLeft: 2, children: /* @__PURE__ */ jsx19(BusyIndicator, { label: "
|
|
4715
|
+
recentBuilds === null ? /* @__PURE__ */ jsx19(Box16, { marginLeft: 2, children: /* @__PURE__ */ jsx19(BusyIndicator, { label: t("home.loadingHistory"), compact: true }) }) : recentBuilds.length === 0 ? /* @__PURE__ */ jsx19(Box16, { marginLeft: 2, children: /* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc600, children: recentError ?? t("home.noJobsYet") }) }) : /* @__PURE__ */ jsx19(Box16, { marginLeft: 2, children: /* @__PURE__ */ jsx19(
|
|
3938
4716
|
SelectList,
|
|
3939
4717
|
{
|
|
3940
4718
|
isActive: homeFocus === "history",
|
|
@@ -3942,7 +4720,7 @@ function App({
|
|
|
3942
4720
|
items: recentBuilds.map((b) => {
|
|
3943
4721
|
const running = !isTerminalStatus(b.status);
|
|
3944
4722
|
return {
|
|
3945
|
-
label: `${b.id.slice(0, 8)} \xB7 ${b.kind === "simulation" ? "sim" : "build"} \xB7 ${b.status}`,
|
|
4723
|
+
label: `${b.id.slice(0, 8)} \xB7 ${b.kind === "simulation" ? t("home.job.kind.sim") : t("home.job.kind.build")} \xB7 ${b.status}`,
|
|
3946
4724
|
value: `job:${b.id}`,
|
|
3947
4725
|
hint: b.simulation_task ? b.simulation_task.slice(0, 50) : b.weights_artifact_id?.slice(0, 8) ?? void 0,
|
|
3948
4726
|
...running ? { prefix: /* @__PURE__ */ jsx19(Twinkle, {}), labelColor: COLORS.emerald } : {}
|
|
@@ -3957,20 +4735,17 @@ function App({
|
|
|
3957
4735
|
] }),
|
|
3958
4736
|
/* @__PURE__ */ jsxs17(Box16, { flexDirection: "row", children: [
|
|
3959
4737
|
/* @__PURE__ */ jsxs17(Box16, { flexDirection: "column", flexShrink: 0, marginRight: 3, children: [
|
|
3960
|
-
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc100, bold: true, children: cfg.activeOrgName ?? "
|
|
4738
|
+
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc100, bold: true, children: cfg.activeOrgName ?? t("home.noActiveOrg") }),
|
|
3961
4739
|
/* @__PURE__ */ jsxs17(Text19, { children: [
|
|
3962
4740
|
/* @__PURE__ */ jsx19(Text19, { color: COLORS.emerald, children: "\u2713 " }),
|
|
3963
|
-
/* @__PURE__ */
|
|
3964
|
-
"session : ",
|
|
3965
|
-
session ?? "\u2014"
|
|
3966
|
-
] })
|
|
4741
|
+
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc500, children: t("home.sessionLabel", { session: session ?? "\u2014" }) })
|
|
3967
4742
|
] }),
|
|
3968
4743
|
logoCells ? /* @__PURE__ */ jsx19(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx19(OrgLogo, { cells: logoCells }) }) : null
|
|
3969
4744
|
] }),
|
|
3970
4745
|
/* @__PURE__ */ jsxs17(Box16, { flexDirection: "column", flexGrow: 1, marginTop: logoCells ? 3 : 0, children: [
|
|
3971
4746
|
/* @__PURE__ */ jsx19(Box16, { children: /* @__PURE__ */ jsxs17(Text19, { color: homeFocus === "menu" ? COLORS.emerald : COLORS.zinc500, children: [
|
|
3972
4747
|
homeFocus === "menu" ? "\u25B8 " : " ",
|
|
3973
|
-
"actions"
|
|
4748
|
+
t("home.actions")
|
|
3974
4749
|
] }) }),
|
|
3975
4750
|
/* @__PURE__ */ jsx19(Box16, { marginLeft: 2, children: /* @__PURE__ */ jsx19(
|
|
3976
4751
|
SelectList,
|
|
@@ -3978,6 +4753,7 @@ function App({
|
|
|
3978
4753
|
isActive: homeFocus === "menu",
|
|
3979
4754
|
showHint: false,
|
|
3980
4755
|
items: menuItems,
|
|
4756
|
+
onIndexChange: setHomeMenuIndex,
|
|
3981
4757
|
onSelect: (i) => {
|
|
3982
4758
|
if (i.value === "job") setPage({ name: "job-source" });
|
|
3983
4759
|
else if (i.value === "simulate") setPage({ name: "simulate-prompt" });
|
|
@@ -3985,6 +4761,7 @@ function App({
|
|
|
3985
4761
|
else if (i.value === "orgs") void loadOrgs({ name: "home" });
|
|
3986
4762
|
else if (i.value === "whoami") void showWhoami();
|
|
3987
4763
|
else if (i.value === "refresh") void reloadRecentBuilds();
|
|
4764
|
+
else if (i.value === "lang") switchLocale(getLocale() === "fr" ? "en" : "fr");
|
|
3988
4765
|
else if (i.value === "logout") void logout();
|
|
3989
4766
|
else if (i.value === "uninstall") setPage({ name: "uninstall-confirm" });
|
|
3990
4767
|
else quit();
|
|
@@ -3997,9 +4774,9 @@ function App({
|
|
|
3997
4774
|
Keycaps,
|
|
3998
4775
|
{
|
|
3999
4776
|
items: [
|
|
4000
|
-
{ key: "\u2191\u2193", desc: "
|
|
4001
|
-
{ key: "tab", desc: "
|
|
4002
|
-
{ key: "enter", desc: "
|
|
4777
|
+
{ key: "\u2191\u2193", desc: t("keycaps.navigate") },
|
|
4778
|
+
{ key: "tab", desc: t("keycaps.switchZone") },
|
|
4779
|
+
{ key: "enter", desc: t("keycaps.validate") }
|
|
4003
4780
|
]
|
|
4004
4781
|
}
|
|
4005
4782
|
) })
|
|
@@ -4014,17 +4791,17 @@ function App({
|
|
|
4014
4791
|
KeyValue,
|
|
4015
4792
|
{
|
|
4016
4793
|
rows: [
|
|
4017
|
-
["user", name || page2.me.email],
|
|
4018
|
-
["email", page2.me.email],
|
|
4019
|
-
["org", cfg.activeOrgName ? `${cfg.activeOrgName} (${cfg.activeOrgId})` : "
|
|
4020
|
-
["session", session ?? "\u2014"]
|
|
4794
|
+
[t("whoami.row.user"), name || page2.me.email],
|
|
4795
|
+
[t("whoami.row.email"), page2.me.email],
|
|
4796
|
+
[t("whoami.row.org"), cfg.activeOrgName ? `${cfg.activeOrgName} (${cfg.activeOrgId})` : t("whoami.org.none")],
|
|
4797
|
+
[t("whoami.row.session"), session ?? "\u2014"]
|
|
4021
4798
|
]
|
|
4022
4799
|
}
|
|
4023
4800
|
),
|
|
4024
4801
|
/* @__PURE__ */ jsx19(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx19(
|
|
4025
4802
|
SelectList,
|
|
4026
4803
|
{
|
|
4027
|
-
items: [backItem("
|
|
4804
|
+
items: [backItem(t("common.backToHome"))],
|
|
4028
4805
|
onSelect: () => back()
|
|
4029
4806
|
}
|
|
4030
4807
|
) })
|
|
@@ -4033,18 +4810,18 @@ function App({
|
|
|
4033
4810
|
}
|
|
4034
4811
|
case "quota": {
|
|
4035
4812
|
const rows2 = [
|
|
4036
|
-
["org", page2.orgName],
|
|
4037
|
-
["
|
|
4813
|
+
[t("whoami.row.org"), page2.orgName],
|
|
4814
|
+
[t("quota.row.remaining"), String(page2.remaining)]
|
|
4038
4815
|
];
|
|
4039
4816
|
if (page2.remaining === 0) {
|
|
4040
|
-
rows2.push(["note", "quota
|
|
4817
|
+
rows2.push([t("quota.row.note"), t("quota.exhausted")]);
|
|
4041
4818
|
}
|
|
4042
4819
|
body = /* @__PURE__ */ jsxs17(Box16, { flexDirection: "column", children: [
|
|
4043
4820
|
/* @__PURE__ */ jsx19(KeyValue, { rows: rows2 }),
|
|
4044
4821
|
/* @__PURE__ */ jsx19(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx19(
|
|
4045
4822
|
SelectList,
|
|
4046
4823
|
{
|
|
4047
|
-
items: [backItem("
|
|
4824
|
+
items: [backItem(t("common.backToHome"))],
|
|
4048
4825
|
onSelect: () => back()
|
|
4049
4826
|
}
|
|
4050
4827
|
) })
|
|
@@ -4056,8 +4833,8 @@ function App({
|
|
|
4056
4833
|
/* @__PURE__ */ jsx19(
|
|
4057
4834
|
TextField,
|
|
4058
4835
|
{
|
|
4059
|
-
title: "
|
|
4060
|
-
placeholder: "
|
|
4836
|
+
title: t("simulate.title"),
|
|
4837
|
+
placeholder: t("simulate.placeholder"),
|
|
4061
4838
|
onCancel: () => back(),
|
|
4062
4839
|
onSubmit: (task) => void startSimulation(task)
|
|
4063
4840
|
}
|
|
@@ -4066,10 +4843,10 @@ function App({
|
|
|
4066
4843
|
Keycaps,
|
|
4067
4844
|
{
|
|
4068
4845
|
items: [
|
|
4069
|
-
{ key: "enter", desc: "
|
|
4070
|
-
{ key: "\\ + enter", desc: "
|
|
4071
|
-
{ key: "\u2190\u2192\u2191\u2193", desc: "
|
|
4072
|
-
{ key: "esc", desc: "
|
|
4846
|
+
{ key: "enter", desc: t("keycaps.send") },
|
|
4847
|
+
{ key: "\\ + enter", desc: t("keycaps.newline") },
|
|
4848
|
+
{ key: "\u2190\u2192\u2191\u2193", desc: t("keycaps.navigate") },
|
|
4849
|
+
{ key: "esc", desc: t("keycaps.back") }
|
|
4073
4850
|
]
|
|
4074
4851
|
}
|
|
4075
4852
|
) })
|
|
@@ -4077,21 +4854,21 @@ function App({
|
|
|
4077
4854
|
break;
|
|
4078
4855
|
case "job-source":
|
|
4079
4856
|
body = /* @__PURE__ */ jsxs17(Box16, { flexDirection: "column", children: [
|
|
4080
|
-
/* @__PURE__ */ jsx19(Box16, { marginBottom: 1, children: /* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc100, bold: true, children: "
|
|
4081
|
-
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc500, children: "
|
|
4857
|
+
/* @__PURE__ */ jsx19(Box16, { marginBottom: 1, children: /* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc100, bold: true, children: t("job.source.title") }) }),
|
|
4858
|
+
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc500, children: t("job.source.question") }),
|
|
4082
4859
|
/* @__PURE__ */ jsx19(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx19(
|
|
4083
4860
|
SelectList,
|
|
4084
4861
|
{
|
|
4085
4862
|
items: [
|
|
4086
4863
|
{
|
|
4087
|
-
label: "
|
|
4864
|
+
label: t("job.source.hf"),
|
|
4088
4865
|
value: "hf",
|
|
4089
|
-
hint:
|
|
4866
|
+
hint: t("job.source.hf.hint")
|
|
4090
4867
|
},
|
|
4091
4868
|
{
|
|
4092
|
-
label: "
|
|
4869
|
+
label: t("job.source.file"),
|
|
4093
4870
|
value: "file",
|
|
4094
|
-
hint: "
|
|
4871
|
+
hint: t("job.source.file.hint")
|
|
4095
4872
|
},
|
|
4096
4873
|
backItem()
|
|
4097
4874
|
],
|
|
@@ -4109,30 +4886,26 @@ function App({
|
|
|
4109
4886
|
/* @__PURE__ */ jsx19(
|
|
4110
4887
|
TextField,
|
|
4111
4888
|
{
|
|
4112
|
-
title: "
|
|
4113
|
-
placeholder: "
|
|
4889
|
+
title: t("job.hf.title"),
|
|
4890
|
+
placeholder: t("job.hf.placeholder"),
|
|
4114
4891
|
onCancel: () => back(),
|
|
4115
4892
|
onSubmit: (v) => void submitHfRepo(v)
|
|
4116
4893
|
}
|
|
4117
4894
|
),
|
|
4118
4895
|
hfTokenHint ? /* @__PURE__ */ jsxs17(Box16, { marginTop: 1, children: [
|
|
4119
|
-
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc600, children: "
|
|
4896
|
+
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc600, children: t("job.hf.tokenLabel") }),
|
|
4120
4897
|
hfTokenHint.account ? /* @__PURE__ */ jsxs17(Text19, { color: COLORS.emerald, children: [
|
|
4121
4898
|
hfTokenHint.account,
|
|
4122
4899
|
" "
|
|
4123
4900
|
] }) : null,
|
|
4124
|
-
/* @__PURE__ */
|
|
4125
|
-
|
|
4126
|
-
hfTokenHint.masked,
|
|
4127
|
-
")"
|
|
4128
|
-
] })
|
|
4129
|
-
] }) : /* @__PURE__ */ jsx19(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc600, children: "aucun token HF configur\xE9 \u2014 ajoutez-en un dans Param\xE8tres org. sur lab.sumdae.fr" }) }),
|
|
4901
|
+
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc500, children: t("job.hf.tokenMasked", { masked: hfTokenHint.masked }) })
|
|
4902
|
+
] }) : /* @__PURE__ */ jsx19(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc600, children: t("job.hf.noToken") }) }),
|
|
4130
4903
|
/* @__PURE__ */ jsx19(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx19(
|
|
4131
4904
|
Keycaps,
|
|
4132
4905
|
{
|
|
4133
4906
|
items: [
|
|
4134
|
-
{ key: "enter", desc: "
|
|
4135
|
-
{ key: "esc", desc: "
|
|
4907
|
+
{ key: "enter", desc: t("keycaps.checkAccess") },
|
|
4908
|
+
{ key: "esc", desc: t("keycaps.back") }
|
|
4136
4909
|
]
|
|
4137
4910
|
}
|
|
4138
4911
|
) })
|
|
@@ -4140,9 +4913,9 @@ function App({
|
|
|
4140
4913
|
break;
|
|
4141
4914
|
case "job-hf-confirm":
|
|
4142
4915
|
body = /* @__PURE__ */ jsxs17(Box16, { flexDirection: "column", children: [
|
|
4143
|
-
/* @__PURE__ */ jsx19(Box16, { marginBottom: 1, children: /* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc100, bold: true, children: "
|
|
4916
|
+
/* @__PURE__ */ jsx19(Box16, { marginBottom: 1, children: /* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc100, bold: true, children: t("job.hfConfirm.title") }) }),
|
|
4144
4917
|
/* @__PURE__ */ jsxs17(Text19, { children: [
|
|
4145
|
-
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc500, children: "repo
|
|
4918
|
+
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc500, children: t("job.hfConfirm.repo") }),
|
|
4146
4919
|
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc100, children: page2.repo }),
|
|
4147
4920
|
page2.revision ? /* @__PURE__ */ jsxs17(Text19, { color: COLORS.zinc500, children: [
|
|
4148
4921
|
" @ ",
|
|
@@ -4150,17 +4923,17 @@ function App({
|
|
|
4150
4923
|
] }) : null
|
|
4151
4924
|
] }),
|
|
4152
4925
|
/* @__PURE__ */ jsxs17(Text19, { children: [
|
|
4153
|
-
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc500, children: "
|
|
4154
|
-
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc100, children: page2.sizeBytes !== null ? formatBytes(page2.sizeBytes) : "
|
|
4155
|
-
page2.gated ? /* @__PURE__ */ jsx19(Text19, { color: COLORS.amber, children: "
|
|
4926
|
+
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc500, children: t("job.hfConfirm.sizeEstimate") }),
|
|
4927
|
+
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc100, children: page2.sizeBytes !== null ? formatBytes(page2.sizeBytes) : t("job.hfConfirm.sizeUnknown") }),
|
|
4928
|
+
page2.gated ? /* @__PURE__ */ jsx19(Text19, { color: COLORS.amber, children: t("job.hfConfirm.gated") }) : null
|
|
4156
4929
|
] }),
|
|
4157
|
-
/* @__PURE__ */ jsx19(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc500, children: "
|
|
4930
|
+
/* @__PURE__ */ jsx19(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc500, children: t("job.hfConfirm.explain") }) }),
|
|
4158
4931
|
/* @__PURE__ */ jsx19(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx19(
|
|
4159
4932
|
SelectList,
|
|
4160
4933
|
{
|
|
4161
4934
|
items: [
|
|
4162
|
-
{ label: "
|
|
4163
|
-
{ label: "
|
|
4935
|
+
{ label: t("job.hfConfirm.launch"), value: "go" },
|
|
4936
|
+
{ label: t("job.hfConfirm.editLink"), value: "edit" },
|
|
4164
4937
|
backItem()
|
|
4165
4938
|
],
|
|
4166
4939
|
onSelect: (i) => {
|
|
@@ -4177,8 +4950,8 @@ function App({
|
|
|
4177
4950
|
/* @__PURE__ */ jsx19(
|
|
4178
4951
|
TextField,
|
|
4179
4952
|
{
|
|
4180
|
-
title: "
|
|
4181
|
-
placeholder: "
|
|
4953
|
+
title: t("job.file.title"),
|
|
4954
|
+
placeholder: t("job.file.placeholder"),
|
|
4182
4955
|
onCancel: () => back(),
|
|
4183
4956
|
onSubmit: (v) => void submitFilePath(v)
|
|
4184
4957
|
}
|
|
@@ -4187,8 +4960,8 @@ function App({
|
|
|
4187
4960
|
Keycaps,
|
|
4188
4961
|
{
|
|
4189
4962
|
items: [
|
|
4190
|
-
{ key: "enter", desc: "
|
|
4191
|
-
{ key: "esc", desc: "
|
|
4963
|
+
{ key: "enter", desc: t("keycaps.validate") },
|
|
4964
|
+
{ key: "esc", desc: t("keycaps.back") }
|
|
4192
4965
|
]
|
|
4193
4966
|
}
|
|
4194
4967
|
) })
|
|
@@ -4196,9 +4969,9 @@ function App({
|
|
|
4196
4969
|
break;
|
|
4197
4970
|
case "job-file-confirm":
|
|
4198
4971
|
body = /* @__PURE__ */ jsxs17(Box16, { flexDirection: "column", children: [
|
|
4199
|
-
/* @__PURE__ */ jsx19(Box16, { marginBottom: 1, children: /* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc100, bold: true, children: "
|
|
4972
|
+
/* @__PURE__ */ jsx19(Box16, { marginBottom: 1, children: /* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc100, bold: true, children: t("job.fileConfirm.title") }) }),
|
|
4200
4973
|
/* @__PURE__ */ jsxs17(Text19, { children: [
|
|
4201
|
-
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc500, children: "
|
|
4974
|
+
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc500, children: t("job.fileConfirm.fileLabel") }),
|
|
4202
4975
|
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc100, children: page2.fileName }),
|
|
4203
4976
|
/* @__PURE__ */ jsxs17(Text19, { color: COLORS.zinc500, children: [
|
|
4204
4977
|
" (",
|
|
@@ -4207,15 +4980,15 @@ function App({
|
|
|
4207
4980
|
] })
|
|
4208
4981
|
] }),
|
|
4209
4982
|
/* @__PURE__ */ jsxs17(Box16, { marginTop: 1, flexDirection: "column", children: [
|
|
4210
|
-
/* @__PURE__ */ jsx19(Text19, { color: COLORS.amber, children: "
|
|
4211
|
-
/* @__PURE__ */ jsx19(Text19, { color: COLORS.amber, children: "
|
|
4983
|
+
/* @__PURE__ */ jsx19(Text19, { color: COLORS.amber, children: t("job.fileConfirm.warnDirect") }),
|
|
4984
|
+
/* @__PURE__ */ jsx19(Text19, { color: COLORS.amber, children: t("job.fileConfirm.warnKeepAlive") })
|
|
4212
4985
|
] }),
|
|
4213
4986
|
/* @__PURE__ */ jsx19(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx19(
|
|
4214
4987
|
SelectList,
|
|
4215
4988
|
{
|
|
4216
4989
|
items: [
|
|
4217
|
-
{ label: "
|
|
4218
|
-
{ label: "
|
|
4990
|
+
{ label: t("job.fileConfirm.gotItLaunch"), value: "go" },
|
|
4991
|
+
{ label: t("job.fileConfirm.changeFile"), value: "edit" },
|
|
4219
4992
|
backItem()
|
|
4220
4993
|
],
|
|
4221
4994
|
onSelect: (i) => {
|
|
@@ -4241,7 +5014,7 @@ function App({
|
|
|
4241
5014
|
onDone: () => setPage({ name: "watch", buildId: page2.buildId }),
|
|
4242
5015
|
onError: (message) => setPage({
|
|
4243
5016
|
name: "error",
|
|
4244
|
-
title: "upload
|
|
5017
|
+
title: t("upload.interrupted.title"),
|
|
4245
5018
|
detail: message,
|
|
4246
5019
|
back: { name: "home" }
|
|
4247
5020
|
})
|
|
@@ -4268,20 +5041,20 @@ function App({
|
|
|
4268
5041
|
const active = !isTerminalStatus(page2.build.status);
|
|
4269
5042
|
const createdAtMs = page2.build.created_at ? Date.parse(page2.build.created_at) : void 0;
|
|
4270
5043
|
body = /* @__PURE__ */ jsxs17(Box16, { flexDirection: "column", children: [
|
|
4271
|
-
/* @__PURE__ */ jsx19(Box16, { marginBottom: 1, children: /* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc500, children: "
|
|
5044
|
+
/* @__PURE__ */ jsx19(Box16, { marginBottom: 1, children: /* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc500, children: t("buildSummary.heading") }) }),
|
|
4272
5045
|
/* @__PURE__ */ jsx19(JobSummary, { build: page2.build }),
|
|
4273
5046
|
/* @__PURE__ */ jsx19(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx19(
|
|
4274
5047
|
SelectList,
|
|
4275
5048
|
{
|
|
4276
5049
|
items: [
|
|
4277
5050
|
active ? {
|
|
4278
|
-
label: "
|
|
5051
|
+
label: t("buildSummary.watchLive"),
|
|
4279
5052
|
value: "rewatch",
|
|
4280
5053
|
labelColor: COLORS.emerald,
|
|
4281
5054
|
prefix: /* @__PURE__ */ jsx19(Twinkle, {})
|
|
4282
|
-
} : { label: "
|
|
4283
|
-
backItem("
|
|
4284
|
-
{ label: "
|
|
5055
|
+
} : { label: t("buildSummary.rewatch"), value: "rewatch", hint: t("buildSummary.rewatch.hint") },
|
|
5056
|
+
backItem(t("common.backToHome")),
|
|
5057
|
+
{ label: t("common.quit"), value: "quit" }
|
|
4285
5058
|
],
|
|
4286
5059
|
onSelect: (i) => {
|
|
4287
5060
|
if (i.value === "rewatch")
|
|
@@ -4317,8 +5090,8 @@ function App({
|
|
|
4317
5090
|
SelectList,
|
|
4318
5091
|
{
|
|
4319
5092
|
items: [
|
|
4320
|
-
{ label: "
|
|
4321
|
-
{ label: "
|
|
5093
|
+
{ label: t("common.back"), value: "back", hint: t("common.orEscape") },
|
|
5094
|
+
{ label: t("common.quit"), value: "quit" }
|
|
4322
5095
|
],
|
|
4323
5096
|
onSelect: (i) => i.value === "back" ? setPage(page2.back) : quit()
|
|
4324
5097
|
}
|
|
@@ -4339,22 +5112,10 @@ function App({
|
|
|
4339
5112
|
justifyContent: "center",
|
|
4340
5113
|
flexDirection: "column",
|
|
4341
5114
|
children: [
|
|
4342
|
-
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc100, bold: true, children: "
|
|
5115
|
+
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc100, bold: true, children: t("common.terminalTooSmall") }),
|
|
4343
5116
|
/* @__PURE__ */ jsxs17(Box16, { marginTop: 1, flexDirection: "column", alignItems: "center", children: [
|
|
4344
|
-
/* @__PURE__ */
|
|
4345
|
-
|
|
4346
|
-
MIN_COLS,
|
|
4347
|
-
"\xD7",
|
|
4348
|
-
MIN_ROWS,
|
|
4349
|
-
" minimum"
|
|
4350
|
-
] }),
|
|
4351
|
-
/* @__PURE__ */ jsxs17(Text19, { color: COLORS.zinc500, wrap: "truncate", children: [
|
|
4352
|
-
"(actuel : ",
|
|
4353
|
-
columns,
|
|
4354
|
-
"\xD7",
|
|
4355
|
-
rows,
|
|
4356
|
-
")"
|
|
4357
|
-
] })
|
|
5117
|
+
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc500, wrap: "truncate", children: t("common.terminalEnlarge", { cols: MIN_COLS, rows: MIN_ROWS }) }),
|
|
5118
|
+
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc500, wrap: "truncate", children: t("common.terminalCurrent", { cols: columns, rows }) })
|
|
4358
5119
|
] })
|
|
4359
5120
|
]
|
|
4360
5121
|
}
|
|
@@ -4646,8 +5407,8 @@ function Banner({ animate, onDone }) {
|
|
|
4646
5407
|
onDone?.();
|
|
4647
5408
|
return;
|
|
4648
5409
|
}
|
|
4649
|
-
const
|
|
4650
|
-
return () => clearTimeout(
|
|
5410
|
+
const t2 = setTimeout(() => setFrame((f) => f + 1), FRAME_MS3);
|
|
5411
|
+
return () => clearTimeout(t2);
|
|
4651
5412
|
}, [animate, frame, onDone]);
|
|
4652
5413
|
const color = colorEnabled();
|
|
4653
5414
|
const angle = 0.9 + frame * 0.05;
|
|
@@ -4657,7 +5418,8 @@ function Banner({ animate, onDone }) {
|
|
|
4657
5418
|
/* @__PURE__ */ jsx20(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx20(Text20, { children: planetFrame(angle, { orbitAngle }, color) }) }),
|
|
4658
5419
|
/* @__PURE__ */ jsx20(Box17, { marginTop: 1, children: /* @__PURE__ */ jsxs18(Text20, { color: COLORS.zinc500, children: [
|
|
4659
5420
|
/* @__PURE__ */ jsx20(Text20, { color: COLORS.emerald, children: "$" }),
|
|
4660
|
-
"
|
|
5421
|
+
" ",
|
|
5422
|
+
t("banner.tagline")
|
|
4661
5423
|
] }) })
|
|
4662
5424
|
] });
|
|
4663
5425
|
}
|
|
@@ -4666,23 +5428,20 @@ function Banner({ animate, onDone }) {
|
|
|
4666
5428
|
import { Box as Box18, Text as Text21 } from "ink";
|
|
4667
5429
|
import { jsx as jsx21, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
4668
5430
|
var COMMANDS = [
|
|
4669
|
-
{ cmd: "sumdae login", desc: "
|
|
4670
|
-
{ cmd: "sumdae whoami", desc: "
|
|
4671
|
-
{ cmd: "sumdae push <fichier>", desc: "
|
|
4672
|
-
{ cmd: "sumdae build <artifact>", desc: "
|
|
4673
|
-
{ cmd: "sumdae watch <buildId>", desc: "
|
|
4674
|
-
{ cmd: "sumdae cancel <buildId>", desc: "
|
|
4675
|
-
{ cmd: "sumdae quota", desc: "
|
|
4676
|
-
{ cmd: "sumdae org list", desc: "
|
|
4677
|
-
{ cmd: "sumdae org switch", desc: "
|
|
4678
|
-
{ cmd: "sumdae logout", desc: "
|
|
5431
|
+
{ cmd: "sumdae login", desc: t("help.login") },
|
|
5432
|
+
{ cmd: "sumdae whoami", desc: t("cli.whoami.description") },
|
|
5433
|
+
{ cmd: "sumdae push <fichier>", desc: t("help.push") },
|
|
5434
|
+
{ cmd: "sumdae build <artifact>", desc: t("help.build") },
|
|
5435
|
+
{ cmd: "sumdae watch <buildId>", desc: t("help.watch") },
|
|
5436
|
+
{ cmd: "sumdae cancel <buildId>", desc: t("help.cancel") },
|
|
5437
|
+
{ cmd: "sumdae quota", desc: t("help.quota") },
|
|
5438
|
+
{ cmd: "sumdae org list", desc: t("cli.org.list.description") },
|
|
5439
|
+
{ cmd: "sumdae org switch", desc: t("cli.org.switch.description") },
|
|
5440
|
+
{ cmd: "sumdae logout", desc: t("help.logout") }
|
|
4679
5441
|
];
|
|
4680
5442
|
function Help({ version }) {
|
|
4681
5443
|
return /* @__PURE__ */ jsxs19(Box18, { flexDirection: "column", children: [
|
|
4682
|
-
/* @__PURE__ */
|
|
4683
|
-
"COMMANDES \xB7 v",
|
|
4684
|
-
version
|
|
4685
|
-
] }),
|
|
5444
|
+
/* @__PURE__ */ jsx21(Text21, { color: COLORS.zinc600, children: t("help.heading", { version }) }),
|
|
4686
5445
|
COMMANDS.map((c, i) => /* @__PURE__ */ jsxs19(Box18, { marginTop: i === 0 ? 1 : 0, children: [
|
|
4687
5446
|
/* @__PURE__ */ jsx21(Box18, { width: 9, children: /* @__PURE__ */ jsx21(Text21, { color: COLORS.zinc600, children: `cmd_${String(i + 1).padStart(2, "0")}` }) }),
|
|
4688
5447
|
/* @__PURE__ */ jsx21(Box18, { width: 22, children: /* @__PURE__ */ jsxs19(Text21, { color: COLORS.zinc100, children: [
|
|
@@ -4720,8 +5479,8 @@ async function homeAction(version) {
|
|
|
4720
5479
|
if (!interactive) {
|
|
4721
5480
|
const cfg2 = loadConfig();
|
|
4722
5481
|
const status = creds ? [
|
|
4723
|
-
creds.kind === "api-key" ? "
|
|
4724
|
-
cfg2.activeOrgName ? `organisation : ${cfg2.activeOrgName}` : "
|
|
5482
|
+
creds.kind === "api-key" ? t("home.static.sessionApiKey") : t("home.static.sessionOauth"),
|
|
5483
|
+
cfg2.activeOrgName ? `organisation : ${cfg2.activeOrgName}` : t("home.static.orgNone")
|
|
4725
5484
|
] : null;
|
|
4726
5485
|
const app2 = render3(/* @__PURE__ */ jsx22(Home, { animate: false, status, version }));
|
|
4727
5486
|
await app2.waitUntilExit();
|
|
@@ -4757,8 +5516,8 @@ var FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u282
|
|
|
4757
5516
|
function Spinner({ label }) {
|
|
4758
5517
|
const [i, setI] = useState11(0);
|
|
4759
5518
|
useEffect10(() => {
|
|
4760
|
-
const
|
|
4761
|
-
return () => clearInterval(
|
|
5519
|
+
const t2 = setInterval(() => setI((x) => (x + 1) % FRAMES.length), 80);
|
|
5520
|
+
return () => clearInterval(t2);
|
|
4762
5521
|
}, []);
|
|
4763
5522
|
return /* @__PURE__ */ jsxs21(Text23, { children: [
|
|
4764
5523
|
/* @__PURE__ */ jsx23(Text23, { color: COLORS.emerald, children: FRAMES[i] }),
|
|
@@ -4773,7 +5532,7 @@ function Spinner({ label }) {
|
|
|
4773
5532
|
import { jsx as jsx24, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
4774
5533
|
function orgItems(orgs, myId) {
|
|
4775
5534
|
return orgs.map((o) => {
|
|
4776
|
-
const role = o.members.find((m) => m.user_id === myId)?.role ?? "member";
|
|
5535
|
+
const role = o.members.find((m) => m.user_id === myId)?.role ?? t("orgs.role.member");
|
|
4777
5536
|
return { label: o.name, value: o._id, hint: `${o.slug} \xB7 ${role}` };
|
|
4778
5537
|
});
|
|
4779
5538
|
}
|
|
@@ -4797,7 +5556,7 @@ function LoginApp({ noBrowser, skipAuth }) {
|
|
|
4797
5556
|
if (orgs.length === 0) {
|
|
4798
5557
|
setPhase({
|
|
4799
5558
|
step: "done",
|
|
4800
|
-
lines: [
|
|
5559
|
+
lines: [t("common.connectedAs", { email: me.email }), t("common.noOrgCreateOnLab")]
|
|
4801
5560
|
});
|
|
4802
5561
|
setTimeout(exit, 10);
|
|
4803
5562
|
return;
|
|
@@ -4805,7 +5564,7 @@ function LoginApp({ noBrowser, skipAuth }) {
|
|
|
4805
5564
|
if (!process.stdin.isTTY) {
|
|
4806
5565
|
setPhase({
|
|
4807
5566
|
step: "done",
|
|
4808
|
-
lines: [
|
|
5567
|
+
lines: [t("common.connectedAs", { email: me.email }), t("login.noOrgCreateThenSwitch")]
|
|
4809
5568
|
});
|
|
4810
5569
|
setTimeout(exit, 10);
|
|
4811
5570
|
return;
|
|
@@ -4816,7 +5575,7 @@ function LoginApp({ noBrowser, skipAuth }) {
|
|
|
4816
5575
|
process.exitCode = 1;
|
|
4817
5576
|
setPhase({
|
|
4818
5577
|
step: "error",
|
|
4819
|
-
title: "
|
|
5578
|
+
title: t("common.loginFailed"),
|
|
4820
5579
|
detail: e instanceof Error ? e.message : String(e)
|
|
4821
5580
|
});
|
|
4822
5581
|
setTimeout(exit, 10);
|
|
@@ -4825,21 +5584,18 @@ function LoginApp({ noBrowser, skipAuth }) {
|
|
|
4825
5584
|
}, []);
|
|
4826
5585
|
if (phase.step === "auth") {
|
|
4827
5586
|
return /* @__PURE__ */ jsxs22(Box20, { flexDirection: "column", children: [
|
|
4828
|
-
/* @__PURE__ */ jsx24(Spinner, { label: "
|
|
5587
|
+
/* @__PURE__ */ jsx24(Spinner, { label: t("common.waitingBrowserLogin") }),
|
|
4829
5588
|
noBrowser && authorizeUrl ? /* @__PURE__ */ jsxs22(Box20, { marginTop: 1, flexDirection: "column", children: [
|
|
4830
|
-
/* @__PURE__ */ jsx24(Text24, { color: COLORS.zinc500, children: "
|
|
5589
|
+
/* @__PURE__ */ jsx24(Text24, { color: COLORS.zinc500, children: t("login.browser.openUrl") }),
|
|
4831
5590
|
/* @__PURE__ */ jsx24(Text24, { color: COLORS.emerald, children: authorizeUrl })
|
|
4832
5591
|
] }) : null
|
|
4833
5592
|
] });
|
|
4834
5593
|
}
|
|
4835
5594
|
if (phase.step === "orgs") {
|
|
4836
5595
|
return /* @__PURE__ */ jsxs22(Box20, { flexDirection: "column", children: [
|
|
4837
|
-
/* @__PURE__ */
|
|
4838
|
-
"connect\xE9 : ",
|
|
4839
|
-
/* @__PURE__ */ jsx24(Text24, { color: COLORS.zinc100, children: phase.me.email })
|
|
4840
|
-
] }),
|
|
5596
|
+
/* @__PURE__ */ jsx24(Text24, { color: COLORS.zinc400, children: t("common.connectedAs", { email: phase.me.email }) }),
|
|
4841
5597
|
/* @__PURE__ */ jsxs22(Box20, { marginTop: 1, flexDirection: "column", children: [
|
|
4842
|
-
/* @__PURE__ */ jsx24(Text24, { color: COLORS.zinc500, children: "
|
|
5598
|
+
/* @__PURE__ */ jsx24(Text24, { color: COLORS.zinc500, children: t("common.activeOrgLabel") }),
|
|
4843
5599
|
/* @__PURE__ */ jsx24(
|
|
4844
5600
|
SelectList,
|
|
4845
5601
|
{
|
|
@@ -4848,7 +5604,7 @@ function LoginApp({ noBrowser, skipAuth }) {
|
|
|
4848
5604
|
const org2 = phase.orgs.find((o) => o._id === item.value);
|
|
4849
5605
|
if (!org2) return;
|
|
4850
5606
|
saveActiveOrg(org2);
|
|
4851
|
-
setPhase({ step: "done", lines: [
|
|
5607
|
+
setPhase({ step: "done", lines: [t("common.activeOrgSet", { name: org2.name })] });
|
|
4852
5608
|
setTimeout(exit, 10);
|
|
4853
5609
|
}
|
|
4854
5610
|
}
|
|
@@ -4866,10 +5622,10 @@ async function loginAction(opts) {
|
|
|
4866
5622
|
if (opts.withKey) {
|
|
4867
5623
|
const { createInterface } = await import("readline/promises");
|
|
4868
5624
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
4869
|
-
const key = (await rl.question(
|
|
5625
|
+
const key = (await rl.question(t("login.key.prompt"))).trim();
|
|
4870
5626
|
rl.close();
|
|
4871
5627
|
if (!key) {
|
|
4872
|
-
console.error("
|
|
5628
|
+
console.error(t("login.noKeyProvided"));
|
|
4873
5629
|
process.exitCode = 1;
|
|
4874
5630
|
return;
|
|
4875
5631
|
}
|
|
@@ -4880,7 +5636,7 @@ async function loginAction(opts) {
|
|
|
4880
5636
|
}
|
|
4881
5637
|
if (!process.stdout.isTTY) {
|
|
4882
5638
|
console.error(
|
|
4883
|
-
"
|
|
5639
|
+
t("login.nonInteractiveTty")
|
|
4884
5640
|
);
|
|
4885
5641
|
process.exitCode = 1;
|
|
4886
5642
|
return;
|
|
@@ -4896,7 +5652,7 @@ async function logoutAction() {
|
|
|
4896
5652
|
delete cfg.activeOrgId;
|
|
4897
5653
|
delete cfg.activeOrgName;
|
|
4898
5654
|
saveConfig(cfg);
|
|
4899
|
-
console.log(ok("
|
|
5655
|
+
console.log(ok(t("logout.done")));
|
|
4900
5656
|
}
|
|
4901
5657
|
|
|
4902
5658
|
// src/commands/org.tsx
|
|
@@ -4912,7 +5668,7 @@ async function fetchOrgItems() {
|
|
|
4912
5668
|
items: orgs.map((o) => ({
|
|
4913
5669
|
label: o.name,
|
|
4914
5670
|
value: o._id,
|
|
4915
|
-
hint: `${o.slug} \xB7 ${o.members.find((m) => m.user_id === me.id)?.role ?? "member"}`
|
|
5671
|
+
hint: `${o.slug} \xB7 ${o.members.find((m) => m.user_id === me.id)?.role ?? t("orgs.role.member")}`
|
|
4916
5672
|
}))
|
|
4917
5673
|
};
|
|
4918
5674
|
}
|
|
@@ -4920,7 +5676,7 @@ async function orgListAction() {
|
|
|
4920
5676
|
try {
|
|
4921
5677
|
const { items } = await fetchOrgItems();
|
|
4922
5678
|
if (items.length === 0) {
|
|
4923
|
-
console.log("
|
|
5679
|
+
console.log(t("common.noOrgCreateOnLab"));
|
|
4924
5680
|
return;
|
|
4925
5681
|
}
|
|
4926
5682
|
const active = loadConfig().activeOrgId;
|
|
@@ -4943,14 +5699,11 @@ function SwitchApp({ items, orgs }) {
|
|
|
4943
5699
|
if (picked) {
|
|
4944
5700
|
return /* @__PURE__ */ jsxs23(Text25, { children: [
|
|
4945
5701
|
/* @__PURE__ */ jsx25(Text25, { color: COLORS.emerald, children: "\u2713 " }),
|
|
4946
|
-
/* @__PURE__ */
|
|
4947
|
-
"organisation active : ",
|
|
4948
|
-
picked.label
|
|
4949
|
-
] })
|
|
5702
|
+
/* @__PURE__ */ jsx25(Text25, { color: COLORS.zinc100, children: t("common.activeOrgSet", { name: picked.label }) })
|
|
4950
5703
|
] });
|
|
4951
5704
|
}
|
|
4952
5705
|
return /* @__PURE__ */ jsxs23(Box21, { flexDirection: "column", children: [
|
|
4953
|
-
/* @__PURE__ */ jsx25(Text25, { color: COLORS.zinc500, children: "
|
|
5706
|
+
/* @__PURE__ */ jsx25(Text25, { color: COLORS.zinc500, children: t("common.activeOrgLabel") }),
|
|
4954
5707
|
/* @__PURE__ */ jsx25(
|
|
4955
5708
|
SelectList,
|
|
4956
5709
|
{
|
|
@@ -4970,11 +5723,11 @@ async function orgSwitchAction() {
|
|
|
4970
5723
|
try {
|
|
4971
5724
|
const { items, orgs } = await fetchOrgItems();
|
|
4972
5725
|
if (items.length === 0) {
|
|
4973
|
-
console.log("
|
|
5726
|
+
console.log(t("common.noOrgCreateOnLab"));
|
|
4974
5727
|
return;
|
|
4975
5728
|
}
|
|
4976
5729
|
if (!process.stdin.isTTY) {
|
|
4977
|
-
console.error("
|
|
5730
|
+
console.error(t("orgs.nonInteractiveTty"));
|
|
4978
5731
|
process.exitCode = 1;
|
|
4979
5732
|
return;
|
|
4980
5733
|
}
|
|
@@ -5002,7 +5755,7 @@ async function hashFile(path, signal) {
|
|
|
5002
5755
|
for await (const chunk of stream) {
|
|
5003
5756
|
if (signal?.aborted) {
|
|
5004
5757
|
stream.destroy();
|
|
5005
|
-
throw new Error("upload
|
|
5758
|
+
throw new Error(t("upload.err.cancelled"));
|
|
5006
5759
|
}
|
|
5007
5760
|
hash.update(chunk);
|
|
5008
5761
|
}
|
|
@@ -5034,7 +5787,7 @@ var PartUrlProvider = class {
|
|
|
5034
5787
|
if (url) return url;
|
|
5035
5788
|
await this.fetchBatch(partNumber);
|
|
5036
5789
|
const retry = this.cache.get(partNumber);
|
|
5037
|
-
if (!retry) throw new Error(
|
|
5790
|
+
if (!retry) throw new Error(t("upload.err.missingPresigned", { n: partNumber }));
|
|
5038
5791
|
return retry;
|
|
5039
5792
|
}
|
|
5040
5793
|
async fetchBatch(from) {
|
|
@@ -5095,7 +5848,7 @@ async function pushArtifact(opts) {
|
|
|
5095
5848
|
const partNumber = next;
|
|
5096
5849
|
if (partNumber > partsTotal) return;
|
|
5097
5850
|
next += 1;
|
|
5098
|
-
if (signal?.aborted) throw new Error("upload
|
|
5851
|
+
if (signal?.aborted) throw new Error(t("upload.err.cancelled"));
|
|
5099
5852
|
const offset = (partNumber - 1) * partSize;
|
|
5100
5853
|
const length = Math.min(partSize, totalBytes - offset);
|
|
5101
5854
|
const buf = Buffer.alloc(length);
|
|
@@ -5107,7 +5860,7 @@ async function pushArtifact(opts) {
|
|
|
5107
5860
|
const res = await fetch(url, { method: "PUT", body: buf, signal });
|
|
5108
5861
|
if (!res.ok) throw new Error(`R2 HTTP ${res.status}`);
|
|
5109
5862
|
const etag = res.headers.get("etag");
|
|
5110
|
-
if (!etag) throw new Error("
|
|
5863
|
+
if (!etag) throw new Error(t("upload.err.missingEtag"));
|
|
5111
5864
|
etags.set(partNumber, etag);
|
|
5112
5865
|
sentBytes += length;
|
|
5113
5866
|
partsDone += 1;
|
|
@@ -5116,13 +5869,18 @@ async function pushArtifact(opts) {
|
|
|
5116
5869
|
break;
|
|
5117
5870
|
} catch (e) {
|
|
5118
5871
|
lastErr = e;
|
|
5119
|
-
if (signal?.aborted) throw new Error("upload
|
|
5872
|
+
if (signal?.aborted) throw new Error(t("upload.err.cancelled"));
|
|
5120
5873
|
if (attempt < maxRetries) await sleep(300 * attempt);
|
|
5121
5874
|
}
|
|
5122
5875
|
}
|
|
5123
5876
|
if (lastErr) {
|
|
5124
5877
|
throw new Error(
|
|
5125
|
-
|
|
5878
|
+
t("upload.err.partFailed", {
|
|
5879
|
+
n: partNumber,
|
|
5880
|
+
total: partsTotal,
|
|
5881
|
+
tries: maxRetries,
|
|
5882
|
+
msg: lastErr instanceof Error ? lastErr.message : String(lastErr)
|
|
5883
|
+
})
|
|
5126
5884
|
);
|
|
5127
5885
|
}
|
|
5128
5886
|
}
|
|
@@ -5227,11 +5985,11 @@ function PushApp({
|
|
|
5227
5985
|
)
|
|
5228
5986
|
] });
|
|
5229
5987
|
}
|
|
5230
|
-
if (phase.step === "error") return /* @__PURE__ */ jsx26(ErrorBox, { title: "push
|
|
5988
|
+
if (phase.step === "error") return /* @__PURE__ */ jsx26(ErrorBox, { title: t("push.failed.title"), detail: phase.msg });
|
|
5231
5989
|
return /* @__PURE__ */ jsxs24(Box22, { flexDirection: "column", children: [
|
|
5232
5990
|
/* @__PURE__ */ jsxs24(Text26, { children: [
|
|
5233
5991
|
/* @__PURE__ */ jsx26(Text26, { color: COLORS.emerald, children: "\u2713 " }),
|
|
5234
|
-
/* @__PURE__ */ jsx26(Text26, { color: COLORS.zinc100, children: "
|
|
5992
|
+
/* @__PURE__ */ jsx26(Text26, { color: COLORS.zinc100, children: t("push.uploaded") })
|
|
5235
5993
|
] }),
|
|
5236
5994
|
/* @__PURE__ */ jsxs24(Text26, { color: COLORS.zinc500, children: [
|
|
5237
5995
|
"id ",
|
|
@@ -5249,14 +6007,14 @@ async function pushAction(filePath2, opts) {
|
|
|
5249
6007
|
const kind = opts.kind ?? inferKind(filePath2);
|
|
5250
6008
|
if (kind !== "weights" && kind !== "pipeline") {
|
|
5251
6009
|
console.error(
|
|
5252
|
-
"
|
|
6010
|
+
t("push.inferKindFailed")
|
|
5253
6011
|
);
|
|
5254
6012
|
process.exitCode = 1;
|
|
5255
6013
|
return;
|
|
5256
6014
|
}
|
|
5257
6015
|
const active = await resolveActiveOrg().catch(() => null);
|
|
5258
6016
|
if (!active) {
|
|
5259
|
-
console.error("
|
|
6017
|
+
console.error(t("common.noActiveOrgRunSwitch"));
|
|
5260
6018
|
process.exitCode = 1;
|
|
5261
6019
|
return;
|
|
5262
6020
|
}
|
|
@@ -5273,17 +6031,17 @@ async function quotaAction() {
|
|
|
5273
6031
|
try {
|
|
5274
6032
|
const active = await resolveActiveOrg();
|
|
5275
6033
|
if (!active) {
|
|
5276
|
-
console.error("
|
|
6034
|
+
console.error(t("common.noActiveOrgRunSwitch"));
|
|
5277
6035
|
process.exitCode = 1;
|
|
5278
6036
|
return;
|
|
5279
6037
|
}
|
|
5280
6038
|
const q = await getOrgQuota(active.slug);
|
|
5281
6039
|
const rows = [
|
|
5282
|
-
["org", `${active.name} (${active.slug})`],
|
|
5283
|
-
["
|
|
6040
|
+
[t("whoami.row.org"), `${active.name} (${active.slug})`],
|
|
6041
|
+
[t("quota.row.remaining"), String(q.remaining)]
|
|
5284
6042
|
];
|
|
5285
6043
|
if (q.remaining === 0) {
|
|
5286
|
-
rows.push(["note", "quota
|
|
6044
|
+
rows.push([t("quota.row.note"), t("quota.exhausted")]);
|
|
5287
6045
|
}
|
|
5288
6046
|
render7(/* @__PURE__ */ jsx27(KeyValue, { rows }));
|
|
5289
6047
|
} catch (e) {
|
|
@@ -5294,10 +6052,10 @@ async function quotaAction() {
|
|
|
5294
6052
|
|
|
5295
6053
|
// src/commands/uninstall.ts
|
|
5296
6054
|
function printPlan(plan) {
|
|
5297
|
-
console.log("
|
|
6055
|
+
console.log(t("uninstall.cli.heading"));
|
|
5298
6056
|
console.log(` canal : ${plan.channel}`);
|
|
5299
6057
|
if (plan.channel === "npm") {
|
|
5300
|
-
console.log(` install : ${plan.manualHint ?? "
|
|
6058
|
+
console.log(` install : ${plan.manualHint ?? t("uninstall.cli.installGlobal")}`);
|
|
5301
6059
|
} else if (plan.installBlockedReason) {
|
|
5302
6060
|
console.log(` install : manuel \u2192 ${plan.manualHint ?? plan.installRoot}`);
|
|
5303
6061
|
} else {
|
|
@@ -5305,14 +6063,14 @@ function printPlan(plan) {
|
|
|
5305
6063
|
if (plan.launcherPath) console.log(` launcher : ${plan.launcherPath}`);
|
|
5306
6064
|
}
|
|
5307
6065
|
console.log(` config : ${plan.configDir}`);
|
|
5308
|
-
console.log("
|
|
6066
|
+
console.log(t("uninstall.cli.credentials"));
|
|
5309
6067
|
}
|
|
5310
6068
|
async function uninstallAction(opts = {}) {
|
|
5311
6069
|
const interactive = process.stdout.isTTY === true && process.stdin.isTTY === true;
|
|
5312
6070
|
if (interactive && !opts.yes) {
|
|
5313
6071
|
const report2 = await runUninstallScreen();
|
|
5314
6072
|
if (!report2) {
|
|
5315
|
-
console.log("
|
|
6073
|
+
console.log(t("uninstall.cli.cancelled"));
|
|
5316
6074
|
return;
|
|
5317
6075
|
}
|
|
5318
6076
|
if (report2.some((s) => s.step !== "install" && !s.ok)) process.exitCode = 1;
|
|
@@ -5326,13 +6084,13 @@ async function uninstallAction(opts = {}) {
|
|
|
5326
6084
|
if (s.ok) {
|
|
5327
6085
|
console.log(ok(s.step));
|
|
5328
6086
|
} else if (s.step === "install") {
|
|
5329
|
-
console.log(warn(`${s.step} \u2014 ${s.error ?? "
|
|
6087
|
+
console.log(warn(`${s.step} \u2014 ${s.error ?? t("uninstall.cli.manualFallback")}`));
|
|
5330
6088
|
} else {
|
|
5331
|
-
console.log(ko(`${s.step} \u2014 ${s.error ?? "
|
|
6089
|
+
console.log(ko(`${s.step} \u2014 ${s.error ?? t("uninstall.cli.stepFailed")}`));
|
|
5332
6090
|
dataFailed = true;
|
|
5333
6091
|
}
|
|
5334
6092
|
}
|
|
5335
|
-
console.log("
|
|
6093
|
+
console.log(t("uninstall.cli.cleaned"));
|
|
5336
6094
|
if (dataFailed) process.exitCode = 1;
|
|
5337
6095
|
}
|
|
5338
6096
|
|
|
@@ -5341,7 +6099,7 @@ import { render as render8 } from "ink";
|
|
|
5341
6099
|
import { jsx as jsx28 } from "react/jsx-runtime";
|
|
5342
6100
|
function machineLine() {
|
|
5343
6101
|
const s = getSystemInfo();
|
|
5344
|
-
return `${s.username}@${s.hostname} \xB7 ${s.localIp ?? "
|
|
6102
|
+
return `${s.username}@${s.hostname} \xB7 ${s.localIp ?? t("whoami.machine.unknownIp")} \xB7 ${s.os} ${s.arch} \xB7 device ${s.deviceId.slice(0, 8)}`;
|
|
5345
6103
|
}
|
|
5346
6104
|
async function whoamiAction() {
|
|
5347
6105
|
try {
|
|
@@ -5349,17 +6107,19 @@ async function whoamiAction() {
|
|
|
5349
6107
|
const cfg = loadConfig();
|
|
5350
6108
|
const creds = await loadCredentials();
|
|
5351
6109
|
const name = `${me.first_name} ${me.last_name}`.trim();
|
|
5352
|
-
const session = creds?.kind === "api-key" ? "
|
|
6110
|
+
const session = creds?.kind === "api-key" ? t("whoami.session.apiKey") : t("whoami.session.oauthExpires", {
|
|
6111
|
+
time: new Date(creds?.expiresAt ?? 0).toLocaleTimeString("fr-FR")
|
|
6112
|
+
});
|
|
5353
6113
|
render8(
|
|
5354
6114
|
/* @__PURE__ */ jsx28(
|
|
5355
6115
|
KeyValue,
|
|
5356
6116
|
{
|
|
5357
6117
|
rows: [
|
|
5358
|
-
["user", name || me.email],
|
|
5359
|
-
["email", me.email],
|
|
5360
|
-
["org", cfg.activeOrgName ? `${cfg.activeOrgName} (${cfg.activeOrgId})` : "
|
|
5361
|
-
["session", session],
|
|
5362
|
-
["machine", machineLine()]
|
|
6118
|
+
[t("whoami.row.user"), name || me.email],
|
|
6119
|
+
[t("whoami.row.email"), me.email],
|
|
6120
|
+
[t("whoami.row.org"), cfg.activeOrgName ? `${cfg.activeOrgName} (${cfg.activeOrgId})` : t("whoami.org.noneSwitch")],
|
|
6121
|
+
[t("whoami.row.session"), session],
|
|
6122
|
+
[t("whoami.row.machine"), machineLine()]
|
|
5363
6123
|
]
|
|
5364
6124
|
}
|
|
5365
6125
|
)
|
|
@@ -5396,7 +6156,7 @@ function UpdateApp({
|
|
|
5396
6156
|
if (channel === "npm") {
|
|
5397
6157
|
setPhase({ kind: "install" });
|
|
5398
6158
|
const ok2 = updateViaNpm(latest.version);
|
|
5399
|
-
if (!ok2) throw new Error("
|
|
6159
|
+
if (!ok2) throw new Error(t("update.err.npmFailed"));
|
|
5400
6160
|
setPhase({ kind: "done" });
|
|
5401
6161
|
setTimeout(() => relaunch(), 300);
|
|
5402
6162
|
return;
|
|
@@ -5404,10 +6164,10 @@ function UpdateApp({
|
|
|
5404
6164
|
const { path, sha256 } = await downloadTarball(latest.tarball_url, (done, total) => {
|
|
5405
6165
|
if (alive) setPhase({ kind: "download", done, total: total || latest.size });
|
|
5406
6166
|
});
|
|
5407
|
-
if (sha256 !== latest.sha256) throw new Error("
|
|
6167
|
+
if (sha256 !== latest.sha256) throw new Error(t("update.err.sha256Mismatch"));
|
|
5408
6168
|
setPhase({ kind: "verify" });
|
|
5409
6169
|
if (!verifyTarball(path, latest.signature)) {
|
|
5410
|
-
throw new Error("
|
|
6170
|
+
throw new Error(t("update.err.invalidSignature"));
|
|
5411
6171
|
}
|
|
5412
6172
|
setPhase({ kind: "install" });
|
|
5413
6173
|
installTarball(path);
|
|
@@ -5441,17 +6201,17 @@ function UpdateApp({
|
|
|
5441
6201
|
suffix: phase.total ? `${fmtBytes3(phase.done)} / ${fmtBytes3(phase.total)}` : fmtBytes3(phase.done)
|
|
5442
6202
|
}
|
|
5443
6203
|
),
|
|
5444
|
-
/* @__PURE__ */ jsx29(Text27, { color: COLORS.zinc500, children:
|
|
6204
|
+
/* @__PURE__ */ jsx29(Text27, { color: COLORS.zinc500, children: t("update.downloading") })
|
|
5445
6205
|
] });
|
|
5446
6206
|
case "verify":
|
|
5447
|
-
return /* @__PURE__ */ jsx29(Text27, { color: COLORS.zinc400, children: "
|
|
6207
|
+
return /* @__PURE__ */ jsx29(Text27, { color: COLORS.zinc400, children: t("update.verifyingSignature") });
|
|
5448
6208
|
case "install":
|
|
5449
|
-
return /* @__PURE__ */ jsx29(Text27, { color: COLORS.zinc400, children: "
|
|
6209
|
+
return /* @__PURE__ */ jsx29(Text27, { color: COLORS.zinc400, children: t("update.installing") });
|
|
5450
6210
|
case "done":
|
|
5451
|
-
return /* @__PURE__ */ jsx29(Text27, { color: COLORS.emerald, children: "
|
|
6211
|
+
return /* @__PURE__ */ jsx29(Text27, { color: COLORS.emerald, children: t("update.doneRestarting") });
|
|
5452
6212
|
case "error":
|
|
5453
6213
|
return /* @__PURE__ */ jsxs25(Fragment3, { children: [
|
|
5454
|
-
/* @__PURE__ */ jsx29(Text27, { color: COLORS.red, children: "
|
|
6214
|
+
/* @__PURE__ */ jsx29(Text27, { color: COLORS.red, children: t("update.failed") }),
|
|
5455
6215
|
/* @__PURE__ */ jsx29(Text27, { color: COLORS.zinc500, wrap: "truncate", children: phase.message })
|
|
5456
6216
|
] });
|
|
5457
6217
|
}
|
|
@@ -5465,7 +6225,7 @@ function UpdateApp({
|
|
|
5465
6225
|
justifyContent: "center",
|
|
5466
6226
|
flexDirection: "column",
|
|
5467
6227
|
children: [
|
|
5468
|
-
/* @__PURE__ */ jsx29(Text27, { color: COLORS.zinc100, bold: true, children: "
|
|
6228
|
+
/* @__PURE__ */ jsx29(Text27, { color: COLORS.zinc100, bold: true, children: t("update.screen.title") }),
|
|
5469
6229
|
/* @__PURE__ */ jsx29(Box23, { marginTop: 1, marginBottom: 1, children: /* @__PURE__ */ jsxs25(Text27, { color: COLORS.zinc500, children: [
|
|
5470
6230
|
"v",
|
|
5471
6231
|
current,
|
|
@@ -5506,35 +6266,34 @@ async function maybeSelfUpdate(argv) {
|
|
|
5506
6266
|
const err = await runUpdateScreen(decision.latest, decision.current);
|
|
5507
6267
|
if (err && decision.forced) {
|
|
5508
6268
|
console.error(
|
|
5509
|
-
|
|
5510
|
-
R\xE9essayez, ou r\xE9installez : https://lab.sumdae.fr/cli`
|
|
6269
|
+
t("update.forcedFailed", { current: decision.current, err })
|
|
5511
6270
|
);
|
|
5512
6271
|
process.exit(1);
|
|
5513
6272
|
}
|
|
5514
6273
|
}
|
|
5515
6274
|
await maybeSelfUpdate(process.argv);
|
|
5516
6275
|
var program = new Command();
|
|
5517
|
-
program.name("sumdae").description("
|
|
6276
|
+
program.name("sumdae").description(t("cli.root.description")).version(CLI_VERSION).action(async () => {
|
|
5518
6277
|
await homeAction(CLI_VERSION);
|
|
5519
6278
|
});
|
|
5520
|
-
program.command("login").description(
|
|
6279
|
+
program.command("login").description(t("cli.login.description")).option("--no-browser", t("cli.login.opt.noBrowser")).option("--with-key", t("cli.login.opt.withKey")).action(async (opts) => {
|
|
5521
6280
|
await loginAction({ noBrowser: !opts.browser, withKey: opts.withKey });
|
|
5522
6281
|
});
|
|
5523
|
-
program.command("logout").description("
|
|
5524
|
-
program.command("whoami").description("
|
|
5525
|
-
program.command("uninstall").description(
|
|
6282
|
+
program.command("logout").description(t("cli.logout.description")).action(logoutAction);
|
|
6283
|
+
program.command("whoami").description(t("cli.whoami.description")).action(whoamiAction);
|
|
6284
|
+
program.command("uninstall").description(t("cli.uninstall.description")).option("--yes", t("cli.uninstall.opt.yes")).action(async (opts) => {
|
|
5526
6285
|
await uninstallAction({ yes: opts.yes });
|
|
5527
6286
|
});
|
|
5528
|
-
program.command("quota").description("
|
|
5529
|
-
program.command("push <fichier>").description("
|
|
5530
|
-
program.command("build <weightsArtifactId>").description("
|
|
5531
|
-
program.command("simulate <task...>").description(
|
|
5532
|
-
program.command("watch <buildId>").description(
|
|
5533
|
-
program.command("cancel <buildId>").description(
|
|
5534
|
-
var agent = program.command("agent").description("
|
|
5535
|
-
agent.command("kill <buildId>").description("
|
|
5536
|
-
agent.command("msg <buildId> <message>").description("
|
|
5537
|
-
var org = program.command("org").description("
|
|
5538
|
-
org.command("list").description("
|
|
5539
|
-
org.command("switch").description("
|
|
6287
|
+
program.command("quota").description(t("cli.quota.description")).action(quotaAction);
|
|
6288
|
+
program.command("push <fichier>").description(t("cli.push.description")).option("--kind <kind>", t("cli.push.opt.kind")).action(pushAction);
|
|
6289
|
+
program.command("build <weightsArtifactId>").description(t("cli.build.description")).option("--pipeline <artifactId>", t("cli.build.opt.pipeline")).action(buildAction);
|
|
6290
|
+
program.command("simulate <task...>").description(t("cli.simulate.description")).action((taskParts) => simulateAction(taskParts.join(" ")));
|
|
6291
|
+
program.command("watch <buildId>").description(t("cli.watch.description")).action(watchAction);
|
|
6292
|
+
program.command("cancel <buildId>").description(t("cli.cancel.description")).action(cancelAction);
|
|
6293
|
+
var agent = program.command("agent").description(t("cli.agent.description"));
|
|
6294
|
+
agent.command("kill <buildId>").description(t("cli.agent.kill.description")).option("--agent <name>", t("cli.agent.opt.agent"), "master").action((buildId, o) => agentCommandAction(buildId, "kill", o));
|
|
6295
|
+
agent.command("msg <buildId> <message>").description(t("cli.agent.msg.description")).option("--agent <name>", t("cli.agent.opt.agent"), "master").action((buildId, message, o) => agentCommandAction(buildId, "message", { ...o, message }));
|
|
6296
|
+
var org = program.command("org").description(t("cli.org.description"));
|
|
6297
|
+
org.command("list").description(t("cli.org.list.description")).action(orgListAction);
|
|
6298
|
+
org.command("switch").description(t("cli.org.switch.description")).action(orgSwitchAction);
|
|
5540
6299
|
await program.parseAsync();
|