@sumdaelive/cli 0.1.2 → 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 +1190 -425
- 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
|
|
|
@@ -2859,9 +3618,10 @@ import { useState as useState6 } from "react";
|
|
|
2859
3618
|
// src/uninstall.ts
|
|
2860
3619
|
import { spawn } from "child_process";
|
|
2861
3620
|
import {
|
|
2862
|
-
|
|
3621
|
+
closeSync,
|
|
2863
3622
|
existsSync as existsSync2,
|
|
2864
3623
|
mkdtempSync as mkdtempSync2,
|
|
3624
|
+
openSync,
|
|
2865
3625
|
readFileSync as readFileSync5,
|
|
2866
3626
|
realpathSync,
|
|
2867
3627
|
rmSync as rmSync3,
|
|
@@ -2906,12 +3666,12 @@ function semverCmp(a, b) {
|
|
|
2906
3666
|
async function fetchLatest() {
|
|
2907
3667
|
try {
|
|
2908
3668
|
const ctrl = new AbortController();
|
|
2909
|
-
const
|
|
3669
|
+
const t2 = setTimeout(() => ctrl.abort(), CHECK_TIMEOUT_MS);
|
|
2910
3670
|
const res = await fetch(`${labUrl()}/cli/latest`, {
|
|
2911
3671
|
signal: ctrl.signal,
|
|
2912
3672
|
headers: { "x-cli-version": CLI_VERSION }
|
|
2913
3673
|
});
|
|
2914
|
-
clearTimeout(
|
|
3674
|
+
clearTimeout(t2);
|
|
2915
3675
|
if (!res.ok) return null;
|
|
2916
3676
|
const j = await res.json();
|
|
2917
3677
|
if (!j.version || !j.tarball_url || !j.signature || !j.sha256) return null;
|
|
@@ -3007,7 +3767,7 @@ function installTarball(tarPath, opts = {}) {
|
|
|
3007
3767
|
const r = spawnSync("tar", ["-xzf", tarPath, "-C", staging], { stdio: "ignore" });
|
|
3008
3768
|
if (r.status !== 0) {
|
|
3009
3769
|
rmSync2(staging, { recursive: true, force: true });
|
|
3010
|
-
throw new Error("
|
|
3770
|
+
throw new Error(t("update.err.extractFailed"));
|
|
3011
3771
|
}
|
|
3012
3772
|
const newDist = join4(staging, "dist");
|
|
3013
3773
|
if (!existsSync(join4(newDist, "main.js"))) {
|
|
@@ -3062,9 +3822,9 @@ function realNorm(p) {
|
|
|
3062
3822
|
}
|
|
3063
3823
|
}
|
|
3064
3824
|
function isDangerousRoot(root) {
|
|
3065
|
-
const
|
|
3066
|
-
if (
|
|
3067
|
-
const n = norm(
|
|
3825
|
+
const t2 = root.trim();
|
|
3826
|
+
if (t2 === "") return true;
|
|
3827
|
+
const n = norm(t2);
|
|
3068
3828
|
if (n === sep) return true;
|
|
3069
3829
|
if (n === norm(homedir2())) return true;
|
|
3070
3830
|
return false;
|
|
@@ -3187,7 +3947,7 @@ async function removeUserData() {
|
|
|
3187
3947
|
function errMsg(e) {
|
|
3188
3948
|
return e instanceof Error ? e.message : String(e);
|
|
3189
3949
|
}
|
|
3190
|
-
function scheduleInstallRemoval(plan) {
|
|
3950
|
+
function scheduleInstallRemoval(plan, opts = {}) {
|
|
3191
3951
|
if (plan.installBlockedReason) {
|
|
3192
3952
|
return { step: "install", ok: false, error: plan.manualHint ?? plan.installBlockedReason };
|
|
3193
3953
|
}
|
|
@@ -3198,24 +3958,29 @@ function scheduleInstallRemoval(plan) {
|
|
|
3198
3958
|
error: plan.manualHint ?? `Supprimez manuellement : ${plan.installRoot}`
|
|
3199
3959
|
};
|
|
3200
3960
|
}
|
|
3961
|
+
const spawnFn = opts.spawnFn ?? spawn;
|
|
3201
3962
|
try {
|
|
3202
3963
|
const scriptDir = mkdtempSync2(join5(tmpdir2(), "sumdae-uninstall-"));
|
|
3203
3964
|
const scriptPath = join5(scriptDir, "uninstall.sh");
|
|
3204
3965
|
const logPath = join5(scriptDir, "uninstall.log");
|
|
3205
3966
|
const text = renderUninstallScript({ ...plan, scriptDir }, process.pid);
|
|
3206
3967
|
writeFileSync5(scriptPath, text, { mode: 448 });
|
|
3207
|
-
const
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3968
|
+
const logFd = openSync(logPath, "a");
|
|
3969
|
+
try {
|
|
3970
|
+
const child = spawnFn("sh", [scriptPath], {
|
|
3971
|
+
detached: true,
|
|
3972
|
+
stdio: ["ignore", logFd, logFd]
|
|
3973
|
+
});
|
|
3974
|
+
child.unref();
|
|
3975
|
+
} finally {
|
|
3976
|
+
closeSync(logFd);
|
|
3977
|
+
}
|
|
3213
3978
|
return { step: "install", ok: true };
|
|
3214
3979
|
} catch (e) {
|
|
3215
3980
|
return {
|
|
3216
3981
|
step: "install",
|
|
3217
3982
|
ok: false,
|
|
3218
|
-
error:
|
|
3983
|
+
error: t("uninstall.scheduleFailed", { err: errMsg(e), manual: plan.manualHint ?? plan.installRoot })
|
|
3219
3984
|
};
|
|
3220
3985
|
}
|
|
3221
3986
|
}
|
|
@@ -3241,20 +4006,22 @@ async function performUninstall(plan) {
|
|
|
3241
4006
|
// src/ui/UninstallScreen.tsx
|
|
3242
4007
|
import { jsx as jsx17, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
3243
4008
|
function channelLabel(c) {
|
|
3244
|
-
return c === "npm" ? "npm
|
|
4009
|
+
return c === "npm" ? t("uninstall.channel.npm") : c === "selfhosted" ? t("uninstall.channel.selfhosted") : t("uninstall.channel.binary");
|
|
3245
4010
|
}
|
|
3246
4011
|
function planRows(plan) {
|
|
3247
|
-
const rows = [["
|
|
4012
|
+
const rows = [[t("uninstall.row.channel"), channelLabel(plan.channel)]];
|
|
4013
|
+
const install = t("uninstall.row.install");
|
|
3248
4014
|
if (plan.channel === "npm") {
|
|
3249
|
-
rows.push(["install",
|
|
4015
|
+
rows.push([install, t("uninstall.install.atClose", { root: plan.manualHint ?? "npm" })]);
|
|
3250
4016
|
} else if (plan.installBlockedReason) {
|
|
3251
|
-
rows.push(["install",
|
|
4017
|
+
rows.push([install, t("uninstall.install.manual", { hint: plan.manualHint ?? plan.installRoot })]);
|
|
3252
4018
|
} else {
|
|
3253
|
-
rows.push(["install",
|
|
3254
|
-
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 })]);
|
|
3255
4022
|
}
|
|
3256
|
-
rows.push(["config",
|
|
3257
|
-
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")]);
|
|
3258
4025
|
return rows;
|
|
3259
4026
|
}
|
|
3260
4027
|
function UninstallView({
|
|
@@ -3271,13 +4038,13 @@ function UninstallView({
|
|
|
3271
4038
|
if (view.kind === "working") {
|
|
3272
4039
|
return /* @__PURE__ */ jsx17(Box15, { flexDirection: "column", children: /* @__PURE__ */ jsxs16(Text17, { color: COLORS.zinc400, children: [
|
|
3273
4040
|
/* @__PURE__ */ jsx17(Text17, { color: COLORS.emerald, children: "\xB7 " }),
|
|
3274
|
-
"
|
|
4041
|
+
t("uninstall.working")
|
|
3275
4042
|
] }) });
|
|
3276
4043
|
}
|
|
3277
4044
|
if (view.kind === "report") {
|
|
3278
4045
|
const dataFailed = view.report.some((s) => s.step !== "install" && !s.ok);
|
|
3279
4046
|
return /* @__PURE__ */ jsxs16(Box15, { flexDirection: "column", children: [
|
|
3280
|
-
/* @__PURE__ */ jsx17(Text17, { color: COLORS.zinc100, bold: true, children: "
|
|
4047
|
+
/* @__PURE__ */ jsx17(Text17, { color: COLORS.zinc100, bold: true, children: t("uninstall.report.title") }),
|
|
3281
4048
|
/* @__PURE__ */ jsx17(Box15, { flexDirection: "column", marginTop: 1, children: view.report.map((s) => /* @__PURE__ */ jsxs16(Box15, { children: [
|
|
3282
4049
|
/* @__PURE__ */ jsx17(Text17, { color: s.ok ? COLORS.emerald : COLORS.red, children: s.ok ? "\u2713 " : "\u2717 " }),
|
|
3283
4050
|
/* @__PURE__ */ jsx17(Text17, { color: COLORS.zinc300, children: s.step }),
|
|
@@ -3286,26 +4053,26 @@ function UninstallView({
|
|
|
3286
4053
|
s.error
|
|
3287
4054
|
] }) : null
|
|
3288
4055
|
] }, s.step)) }),
|
|
3289
|
-
/* @__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") }) }),
|
|
3290
4057
|
/* @__PURE__ */ jsx17(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx17(
|
|
3291
4058
|
SelectList,
|
|
3292
4059
|
{
|
|
3293
|
-
items: [{ label: "
|
|
4060
|
+
items: [{ label: t("uninstall.close"), value: "close" }],
|
|
3294
4061
|
onSelect: () => onDone(view.report)
|
|
3295
4062
|
}
|
|
3296
4063
|
) })
|
|
3297
4064
|
] });
|
|
3298
4065
|
}
|
|
3299
4066
|
return /* @__PURE__ */ jsxs16(Box15, { flexDirection: "column", children: [
|
|
3300
|
-
/* @__PURE__ */ jsx17(Text17, { color: COLORS.zinc100, bold: true, children: "
|
|
3301
|
-
/* @__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") }) }),
|
|
3302
4069
|
/* @__PURE__ */ jsx17(KeyValue, { rows: planRows(plan) }),
|
|
3303
4070
|
/* @__PURE__ */ jsx17(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx17(
|
|
3304
4071
|
SelectList,
|
|
3305
4072
|
{
|
|
3306
4073
|
items: [
|
|
3307
|
-
{ label: "
|
|
3308
|
-
{ label: "
|
|
4074
|
+
{ label: t("uninstall.cancel"), value: "cancel", hint: t("uninstall.cancel.hint") },
|
|
4075
|
+
{ label: t("uninstall.confirmDelete"), value: "go", labelColor: COLORS.red }
|
|
3309
4076
|
],
|
|
3310
4077
|
onSelect: (i) => {
|
|
3311
4078
|
if (i.value === "go") void run();
|
|
@@ -3349,8 +4116,8 @@ var FRAME_MS2 = 120;
|
|
|
3349
4116
|
function Twinkle({ color = COLORS.emerald }) {
|
|
3350
4117
|
const [frame, setFrame] = useState7(0);
|
|
3351
4118
|
useEffect5(() => {
|
|
3352
|
-
const
|
|
3353
|
-
return () => clearInterval(
|
|
4119
|
+
const t2 = setInterval(() => setFrame((f) => (f + 1) % TWINKLE_CYCLE2.length), FRAME_MS2);
|
|
4120
|
+
return () => clearInterval(t2);
|
|
3354
4121
|
}, []);
|
|
3355
4122
|
return /* @__PURE__ */ jsx18(Text18, { color, children: TWINKLE_CYCLE2[frame] });
|
|
3356
4123
|
}
|
|
@@ -3422,15 +4189,15 @@ function NoOrgPage({
|
|
|
3422
4189
|
onQuit
|
|
3423
4190
|
}) {
|
|
3424
4191
|
return /* @__PURE__ */ jsxs17(Box16, { flexDirection: "column", children: [
|
|
3425
|
-
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc100, children: "
|
|
3426
|
-
/* @__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") }),
|
|
3427
4194
|
/* @__PURE__ */ jsx19(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx19(
|
|
3428
4195
|
SelectList,
|
|
3429
4196
|
{
|
|
3430
4197
|
items: [
|
|
3431
|
-
{ label: "
|
|
3432
|
-
{ label: "
|
|
3433
|
-
{ 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" }
|
|
3434
4201
|
],
|
|
3435
4202
|
onSelect: (i) => {
|
|
3436
4203
|
if (i.value === "retry") onRetry();
|
|
@@ -3450,6 +4217,12 @@ function App({
|
|
|
3450
4217
|
const { exit } = useApp3();
|
|
3451
4218
|
const { columns, rows } = useTerminalSize();
|
|
3452
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;
|
|
3453
4226
|
const [page2, setPageState] = useState9(
|
|
3454
4227
|
initialSession ? { name: "home" } : { name: "landing" }
|
|
3455
4228
|
);
|
|
@@ -3478,10 +4251,10 @@ function App({
|
|
|
3478
4251
|
setPageState(p);
|
|
3479
4252
|
};
|
|
3480
4253
|
const back = () => setPage(parentOf(page2));
|
|
3481
|
-
const backItem = (label = "
|
|
4254
|
+
const backItem = (label = t("common.back")) => ({
|
|
3482
4255
|
label,
|
|
3483
4256
|
value: "__back__",
|
|
3484
|
-
hint: "
|
|
4257
|
+
hint: t("common.orEscape")
|
|
3485
4258
|
});
|
|
3486
4259
|
const [recentBuilds, setRecentBuilds] = useState9(null);
|
|
3487
4260
|
const [recentError, setRecentError] = useState9(null);
|
|
@@ -3495,6 +4268,17 @@ function App({
|
|
|
3495
4268
|
},
|
|
3496
4269
|
{ isActive: page2.name === "home" }
|
|
3497
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
|
+
);
|
|
3498
4282
|
const ESCAPE_OWNED = /* @__PURE__ */ new Set([
|
|
3499
4283
|
"home",
|
|
3500
4284
|
"landing",
|
|
@@ -3551,7 +4335,7 @@ function App({
|
|
|
3551
4335
|
};
|
|
3552
4336
|
}, [page2.name]);
|
|
3553
4337
|
const startSimulation = async (task) => {
|
|
3554
|
-
setPage({ name: "loading", label: "
|
|
4338
|
+
setPage({ name: "loading", label: t("simulate.creating") });
|
|
3555
4339
|
try {
|
|
3556
4340
|
const active = await resolveActiveOrg();
|
|
3557
4341
|
if (!active) {
|
|
@@ -3561,7 +4345,7 @@ function App({
|
|
|
3561
4345
|
const buildId = await createSimulation(active.slug, task);
|
|
3562
4346
|
setPage({ name: "watch", buildId });
|
|
3563
4347
|
} catch (e) {
|
|
3564
|
-
toError(e, "
|
|
4348
|
+
toError(e, t("simulate.impossible"), { name: "home" });
|
|
3565
4349
|
}
|
|
3566
4350
|
};
|
|
3567
4351
|
const hfErrorPage = (e) => {
|
|
@@ -3571,38 +4355,38 @@ function App({
|
|
|
3571
4355
|
case "no_token":
|
|
3572
4356
|
return {
|
|
3573
4357
|
name: "error",
|
|
3574
|
-
title: "
|
|
3575
|
-
detail: "
|
|
4358
|
+
title: t("job.hf.err.noToken.title"),
|
|
4359
|
+
detail: t("job.hf.err.noToken.detail"),
|
|
3576
4360
|
back: back2
|
|
3577
4361
|
};
|
|
3578
4362
|
case "invalid_token":
|
|
3579
4363
|
return {
|
|
3580
4364
|
name: "error",
|
|
3581
|
-
title: "
|
|
3582
|
-
detail: "
|
|
4365
|
+
title: t("job.hf.err.invalidToken.title"),
|
|
4366
|
+
detail: t("job.hf.err.invalidToken.detail"),
|
|
3583
4367
|
back: back2
|
|
3584
4368
|
};
|
|
3585
4369
|
case "gated_or_forbidden":
|
|
3586
4370
|
return {
|
|
3587
4371
|
name: "error",
|
|
3588
|
-
title: "
|
|
3589
|
-
detail: "
|
|
4372
|
+
title: t("job.hf.err.gated.title"),
|
|
4373
|
+
detail: t("job.hf.err.gated.detail"),
|
|
3590
4374
|
back: back2
|
|
3591
4375
|
};
|
|
3592
4376
|
case "not_found":
|
|
3593
4377
|
return {
|
|
3594
4378
|
name: "error",
|
|
3595
|
-
title: "
|
|
3596
|
-
detail: "
|
|
4379
|
+
title: t("job.hf.err.notFound.title"),
|
|
4380
|
+
detail: t("job.hf.err.notFound.detail"),
|
|
3597
4381
|
back: back2
|
|
3598
4382
|
};
|
|
3599
4383
|
default:
|
|
3600
|
-
return { name: "error", title: "
|
|
4384
|
+
return { name: "error", title: t("job.hf.err.checkFailed.title"), detail: e.message, back: back2 };
|
|
3601
4385
|
}
|
|
3602
4386
|
}
|
|
3603
4387
|
return {
|
|
3604
4388
|
name: "error",
|
|
3605
|
-
title: "
|
|
4389
|
+
title: t("job.hf.err.checkFailed.title"),
|
|
3606
4390
|
detail: e instanceof Error ? e.message : String(e),
|
|
3607
4391
|
back: back2
|
|
3608
4392
|
};
|
|
@@ -3612,13 +4396,13 @@ function App({
|
|
|
3612
4396
|
if (!parsed) {
|
|
3613
4397
|
setPage({
|
|
3614
4398
|
name: "error",
|
|
3615
|
-
title: "
|
|
3616
|
-
detail: "
|
|
4399
|
+
title: t("job.hf.invalidRef.title"),
|
|
4400
|
+
detail: t("job.hf.invalidRef.detail"),
|
|
3617
4401
|
back: { name: "job-hf" }
|
|
3618
4402
|
});
|
|
3619
4403
|
return;
|
|
3620
4404
|
}
|
|
3621
|
-
setPage({ name: "loading", label: "
|
|
4405
|
+
setPage({ name: "loading", label: t("job.hf.checking") });
|
|
3622
4406
|
try {
|
|
3623
4407
|
const active = await resolveActiveOrg();
|
|
3624
4408
|
if (!active) {
|
|
@@ -3638,7 +4422,7 @@ function App({
|
|
|
3638
4422
|
}
|
|
3639
4423
|
};
|
|
3640
4424
|
const startHfJob = async (repo, revision) => {
|
|
3641
|
-
setPage({ name: "loading", label: "
|
|
4425
|
+
setPage({ name: "loading", label: t("common.creatingJob") });
|
|
3642
4426
|
try {
|
|
3643
4427
|
const active = await resolveActiveOrg();
|
|
3644
4428
|
if (!active) {
|
|
@@ -3651,7 +4435,7 @@ function App({
|
|
|
3651
4435
|
if (e instanceof ApiError && ["no_token", "invalid_token", "gated_or_forbidden", "not_found"].includes(e.code)) {
|
|
3652
4436
|
setPage(hfErrorPage(e));
|
|
3653
4437
|
} else {
|
|
3654
|
-
toError(e, "
|
|
4438
|
+
toError(e, t("common.jobImpossible"), { name: "home" });
|
|
3655
4439
|
}
|
|
3656
4440
|
}
|
|
3657
4441
|
};
|
|
@@ -3671,8 +4455,8 @@ function App({
|
|
|
3671
4455
|
if (!st.isFile()) {
|
|
3672
4456
|
setPage({
|
|
3673
4457
|
name: "error",
|
|
3674
|
-
title: "
|
|
3675
|
-
detail:
|
|
4458
|
+
title: t("job.file.err.notFile.title"),
|
|
4459
|
+
detail: t("job.file.err.notFile.detail", { path: p }),
|
|
3676
4460
|
back: { name: "job-file" }
|
|
3677
4461
|
});
|
|
3678
4462
|
return;
|
|
@@ -3681,7 +4465,7 @@ function App({
|
|
|
3681
4465
|
} catch {
|
|
3682
4466
|
setPage({
|
|
3683
4467
|
name: "error",
|
|
3684
|
-
title: "
|
|
4468
|
+
title: t("job.file.err.notFound.title"),
|
|
3685
4469
|
detail: p,
|
|
3686
4470
|
back: { name: "job-file" }
|
|
3687
4471
|
});
|
|
@@ -3690,7 +4474,7 @@ function App({
|
|
|
3690
4474
|
if (size <= 0) {
|
|
3691
4475
|
setPage({
|
|
3692
4476
|
name: "error",
|
|
3693
|
-
title: "
|
|
4477
|
+
title: t("job.file.err.empty.title"),
|
|
3694
4478
|
detail: p,
|
|
3695
4479
|
back: { name: "job-file" }
|
|
3696
4480
|
});
|
|
@@ -3699,7 +4483,7 @@ function App({
|
|
|
3699
4483
|
setPage({ name: "job-file-confirm", filePath: p, fileName: path.basename(p), sizeBytes: size });
|
|
3700
4484
|
};
|
|
3701
4485
|
const startDirectJob = async (filePath2, fileName, sizeBytes) => {
|
|
3702
|
-
setPage({ name: "loading", label: "
|
|
4486
|
+
setPage({ name: "loading", label: t("common.creatingJob") });
|
|
3703
4487
|
try {
|
|
3704
4488
|
const active = await resolveActiveOrg();
|
|
3705
4489
|
if (!active) {
|
|
@@ -3713,8 +4497,8 @@ function App({
|
|
|
3713
4497
|
});
|
|
3714
4498
|
if (!created.upload_token) {
|
|
3715
4499
|
toError(
|
|
3716
|
-
new Error("
|
|
3717
|
-
"
|
|
4500
|
+
new Error(t("job.noUploadToken")),
|
|
4501
|
+
t("common.jobImpossible"),
|
|
3718
4502
|
{ name: "home" }
|
|
3719
4503
|
);
|
|
3720
4504
|
return;
|
|
@@ -3728,11 +4512,11 @@ function App({
|
|
|
3728
4512
|
sizeBytes
|
|
3729
4513
|
});
|
|
3730
4514
|
} catch (e) {
|
|
3731
|
-
toError(e, "
|
|
4515
|
+
toError(e, t("common.jobImpossible"), { name: "home" });
|
|
3732
4516
|
}
|
|
3733
4517
|
};
|
|
3734
4518
|
const openBuildSummary = async (buildId, opts = {}) => {
|
|
3735
|
-
if (!opts.quiet) setPage({ name: "loading", label: "
|
|
4519
|
+
if (!opts.quiet) setPage({ name: "loading", label: t("job.fetching") });
|
|
3736
4520
|
try {
|
|
3737
4521
|
const active = await resolveActiveOrg();
|
|
3738
4522
|
if (!active) {
|
|
@@ -3742,18 +4526,18 @@ function App({
|
|
|
3742
4526
|
const build = await getBuild(active.slug, buildId);
|
|
3743
4527
|
setPage({ name: "build-summary", build });
|
|
3744
4528
|
} catch (e) {
|
|
3745
|
-
toError(e, "job
|
|
4529
|
+
toError(e, t("job.notFound"), { name: "home" });
|
|
3746
4530
|
}
|
|
3747
4531
|
};
|
|
3748
4532
|
const loadOrgs = async (back2) => {
|
|
3749
|
-
setPage({ name: "loading", label: "
|
|
4533
|
+
setPage({ name: "loading", label: t("orgs.loading") });
|
|
3750
4534
|
try {
|
|
3751
4535
|
const me = await labApi("/me");
|
|
3752
4536
|
const orgs = await labApi("/orgs");
|
|
3753
4537
|
if (orgs.length === 0) setPage({ name: "no-org" });
|
|
3754
4538
|
else setPage({ name: "orgs", me, orgs });
|
|
3755
4539
|
} catch (e) {
|
|
3756
|
-
toError(e, "
|
|
4540
|
+
toError(e, t("orgs.fetchFailed"), back2);
|
|
3757
4541
|
}
|
|
3758
4542
|
};
|
|
3759
4543
|
const startBrowserLogin = async () => {
|
|
@@ -3768,19 +4552,19 @@ function App({
|
|
|
3768
4552
|
setSession("oauth");
|
|
3769
4553
|
await loadOrgs({ name: "landing" });
|
|
3770
4554
|
} catch (e) {
|
|
3771
|
-
toError(e, "
|
|
4555
|
+
toError(e, t("common.loginFailed"), { name: "landing" });
|
|
3772
4556
|
}
|
|
3773
4557
|
};
|
|
3774
4558
|
const submitKey = async (key) => {
|
|
3775
4559
|
const trimmed = key.trim();
|
|
3776
4560
|
if (!trimmed) return;
|
|
3777
|
-
setPage({ name: "loading", label: "
|
|
4561
|
+
setPage({ name: "loading", label: t("login.validatingKey") });
|
|
3778
4562
|
try {
|
|
3779
4563
|
await saveCredentials({ kind: "api-key", apiKey: trimmed });
|
|
3780
4564
|
await labApi("/me");
|
|
3781
4565
|
} catch (e) {
|
|
3782
4566
|
await clearCredentials();
|
|
3783
|
-
toError(e, "
|
|
4567
|
+
toError(e, t("login.invalidKey"), { name: "login-key" });
|
|
3784
4568
|
return;
|
|
3785
4569
|
}
|
|
3786
4570
|
setSession("api-key");
|
|
@@ -3791,7 +4575,7 @@ function App({
|
|
|
3791
4575
|
setPage({ name: "home" });
|
|
3792
4576
|
};
|
|
3793
4577
|
const showQuota = async () => {
|
|
3794
|
-
setPage({ name: "loading", label: "quota
|
|
4578
|
+
setPage({ name: "loading", label: t("quota.loading") });
|
|
3795
4579
|
try {
|
|
3796
4580
|
const active = await resolveActiveOrg();
|
|
3797
4581
|
if (!active) {
|
|
@@ -3801,20 +4585,20 @@ function App({
|
|
|
3801
4585
|
const q = await getOrgQuota(active.slug);
|
|
3802
4586
|
setPage({ name: "quota", orgName: active.name, remaining: q.remaining });
|
|
3803
4587
|
} catch (e) {
|
|
3804
|
-
toError(e, "quota
|
|
4588
|
+
toError(e, t("quota.unreachable"), { name: "home" });
|
|
3805
4589
|
}
|
|
3806
4590
|
};
|
|
3807
4591
|
const showWhoami = async () => {
|
|
3808
|
-
setPage({ name: "loading", label: "
|
|
4592
|
+
setPage({ name: "loading", label: t("whoami.loading") });
|
|
3809
4593
|
try {
|
|
3810
4594
|
const me = await labApi("/me");
|
|
3811
4595
|
setPage({ name: "whoami", me });
|
|
3812
4596
|
} catch (e) {
|
|
3813
|
-
toError(e, "
|
|
4597
|
+
toError(e, t("whoami.unreachable"), { name: "home" });
|
|
3814
4598
|
}
|
|
3815
4599
|
};
|
|
3816
4600
|
const logout = async () => {
|
|
3817
|
-
setPage({ name: "loading", label: "
|
|
4601
|
+
setPage({ name: "loading", label: t("common.signingOut") });
|
|
3818
4602
|
await clearCredentials();
|
|
3819
4603
|
const cfg = loadConfig();
|
|
3820
4604
|
delete cfg.activeOrgId;
|
|
@@ -3827,14 +4611,14 @@ function App({
|
|
|
3827
4611
|
switch (page2.name) {
|
|
3828
4612
|
case "landing":
|
|
3829
4613
|
body = /* @__PURE__ */ jsxs17(Box16, { flexDirection: "column", children: [
|
|
3830
|
-
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc500, children: "
|
|
4614
|
+
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc500, children: t("landing.howConnect") }),
|
|
3831
4615
|
/* @__PURE__ */ jsx19(
|
|
3832
4616
|
SelectList,
|
|
3833
4617
|
{
|
|
3834
4618
|
items: [
|
|
3835
|
-
{ label: "
|
|
3836
|
-
{ label: "
|
|
3837
|
-
{ 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") }
|
|
3838
4622
|
],
|
|
3839
4623
|
onSelect: (i) => {
|
|
3840
4624
|
if (i.value === "browser") void startBrowserLogin();
|
|
@@ -3847,9 +4631,9 @@ function App({
|
|
|
3847
4631
|
break;
|
|
3848
4632
|
case "login-browser":
|
|
3849
4633
|
body = /* @__PURE__ */ jsxs17(Box16, { flexDirection: "column", children: [
|
|
3850
|
-
/* @__PURE__ */ jsx19(BusyIndicator, { label: "
|
|
4634
|
+
/* @__PURE__ */ jsx19(BusyIndicator, { label: t("common.waitingBrowserLogin"), compact: true }),
|
|
3851
4635
|
page2.url ? /* @__PURE__ */ jsxs17(Box16, { marginTop: 1, flexDirection: "column", children: [
|
|
3852
|
-
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc600, children: "
|
|
4636
|
+
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc600, children: t("login.browser.copyUrl") }),
|
|
3853
4637
|
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc400, children: page2.url })
|
|
3854
4638
|
] }) : null
|
|
3855
4639
|
] });
|
|
@@ -3859,13 +4643,13 @@ function App({
|
|
|
3859
4643
|
/* @__PURE__ */ jsx19(
|
|
3860
4644
|
TextField,
|
|
3861
4645
|
{
|
|
3862
|
-
title: "
|
|
3863
|
-
placeholder: "
|
|
4646
|
+
title: t("login.key.title"),
|
|
4647
|
+
placeholder: t("login.key.placeholder"),
|
|
3864
4648
|
onSubmit: (v) => void submitKey(v),
|
|
3865
4649
|
onCancel: () => back()
|
|
3866
4650
|
}
|
|
3867
4651
|
),
|
|
3868
|
-
/* @__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") }] }) })
|
|
3869
4653
|
] });
|
|
3870
4654
|
break;
|
|
3871
4655
|
case "loading":
|
|
@@ -3876,19 +4660,16 @@ function App({
|
|
|
3876
4660
|
break;
|
|
3877
4661
|
case "orgs":
|
|
3878
4662
|
body = /* @__PURE__ */ jsxs17(Box16, { flexDirection: "column", children: [
|
|
3879
|
-
/* @__PURE__ */
|
|
3880
|
-
"connect\xE9 : ",
|
|
3881
|
-
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc100, children: page2.me.email })
|
|
3882
|
-
] }),
|
|
4663
|
+
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc400, children: t("common.connectedAs", { email: page2.me.email }) }),
|
|
3883
4664
|
/* @__PURE__ */ jsxs17(Box16, { marginTop: 1, flexDirection: "column", children: [
|
|
3884
|
-
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc500, children: "
|
|
4665
|
+
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc500, children: t("common.activeOrgLabel") }),
|
|
3885
4666
|
/* @__PURE__ */ jsx19(
|
|
3886
4667
|
SelectList,
|
|
3887
4668
|
{
|
|
3888
4669
|
items: page2.orgs.map((o) => ({
|
|
3889
4670
|
label: o.name,
|
|
3890
4671
|
value: o._id,
|
|
3891
|
-
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")}`
|
|
3892
4673
|
})),
|
|
3893
4674
|
onSelect: (item) => {
|
|
3894
4675
|
const org2 = page2.orgs.find((o) => o._id === item.value);
|
|
@@ -3911,24 +4692,27 @@ function App({
|
|
|
3911
4692
|
break;
|
|
3912
4693
|
case "home": {
|
|
3913
4694
|
const cfg = loadConfig();
|
|
4695
|
+
const langLabel = `Langue / Language : ${getLocale() === "fr" ? "Fran\xE7ais" : "English"} \u203A`;
|
|
3914
4696
|
const menuItems = [
|
|
3915
|
-
{ label: "
|
|
3916
|
-
{ label: "
|
|
3917
|
-
{ label: "
|
|
3918
|
-
{ label: "
|
|
3919
|
-
{ label: "
|
|
3920
|
-
{ label: "
|
|
3921
|
-
{ label:
|
|
3922
|
-
{ label: "
|
|
3923
|
-
{ 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" }
|
|
3924
4707
|
];
|
|
4708
|
+
homeLangIndexRef.current = menuItems.findIndex((i) => i.value === "lang");
|
|
3925
4709
|
body = /* @__PURE__ */ jsxs17(Box16, { flexDirection: "column", children: [
|
|
3926
4710
|
/* @__PURE__ */ jsxs17(Box16, { flexDirection: "column", marginBottom: 1, children: [
|
|
3927
4711
|
/* @__PURE__ */ jsx19(Box16, { children: /* @__PURE__ */ jsxs17(Text19, { color: homeFocus === "history" ? COLORS.emerald : COLORS.zinc500, children: [
|
|
3928
4712
|
homeFocus === "history" ? "\u25B8 " : " ",
|
|
3929
|
-
"
|
|
4713
|
+
t("home.recentJobs")
|
|
3930
4714
|
] }) }),
|
|
3931
|
-
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(
|
|
3932
4716
|
SelectList,
|
|
3933
4717
|
{
|
|
3934
4718
|
isActive: homeFocus === "history",
|
|
@@ -3936,7 +4720,7 @@ function App({
|
|
|
3936
4720
|
items: recentBuilds.map((b) => {
|
|
3937
4721
|
const running = !isTerminalStatus(b.status);
|
|
3938
4722
|
return {
|
|
3939
|
-
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}`,
|
|
3940
4724
|
value: `job:${b.id}`,
|
|
3941
4725
|
hint: b.simulation_task ? b.simulation_task.slice(0, 50) : b.weights_artifact_id?.slice(0, 8) ?? void 0,
|
|
3942
4726
|
...running ? { prefix: /* @__PURE__ */ jsx19(Twinkle, {}), labelColor: COLORS.emerald } : {}
|
|
@@ -3951,20 +4735,17 @@ function App({
|
|
|
3951
4735
|
] }),
|
|
3952
4736
|
/* @__PURE__ */ jsxs17(Box16, { flexDirection: "row", children: [
|
|
3953
4737
|
/* @__PURE__ */ jsxs17(Box16, { flexDirection: "column", flexShrink: 0, marginRight: 3, children: [
|
|
3954
|
-
/* @__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") }),
|
|
3955
4739
|
/* @__PURE__ */ jsxs17(Text19, { children: [
|
|
3956
4740
|
/* @__PURE__ */ jsx19(Text19, { color: COLORS.emerald, children: "\u2713 " }),
|
|
3957
|
-
/* @__PURE__ */
|
|
3958
|
-
"session : ",
|
|
3959
|
-
session ?? "\u2014"
|
|
3960
|
-
] })
|
|
4741
|
+
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc500, children: t("home.sessionLabel", { session: session ?? "\u2014" }) })
|
|
3961
4742
|
] }),
|
|
3962
4743
|
logoCells ? /* @__PURE__ */ jsx19(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx19(OrgLogo, { cells: logoCells }) }) : null
|
|
3963
4744
|
] }),
|
|
3964
4745
|
/* @__PURE__ */ jsxs17(Box16, { flexDirection: "column", flexGrow: 1, marginTop: logoCells ? 3 : 0, children: [
|
|
3965
4746
|
/* @__PURE__ */ jsx19(Box16, { children: /* @__PURE__ */ jsxs17(Text19, { color: homeFocus === "menu" ? COLORS.emerald : COLORS.zinc500, children: [
|
|
3966
4747
|
homeFocus === "menu" ? "\u25B8 " : " ",
|
|
3967
|
-
"actions"
|
|
4748
|
+
t("home.actions")
|
|
3968
4749
|
] }) }),
|
|
3969
4750
|
/* @__PURE__ */ jsx19(Box16, { marginLeft: 2, children: /* @__PURE__ */ jsx19(
|
|
3970
4751
|
SelectList,
|
|
@@ -3972,6 +4753,7 @@ function App({
|
|
|
3972
4753
|
isActive: homeFocus === "menu",
|
|
3973
4754
|
showHint: false,
|
|
3974
4755
|
items: menuItems,
|
|
4756
|
+
onIndexChange: setHomeMenuIndex,
|
|
3975
4757
|
onSelect: (i) => {
|
|
3976
4758
|
if (i.value === "job") setPage({ name: "job-source" });
|
|
3977
4759
|
else if (i.value === "simulate") setPage({ name: "simulate-prompt" });
|
|
@@ -3979,6 +4761,7 @@ function App({
|
|
|
3979
4761
|
else if (i.value === "orgs") void loadOrgs({ name: "home" });
|
|
3980
4762
|
else if (i.value === "whoami") void showWhoami();
|
|
3981
4763
|
else if (i.value === "refresh") void reloadRecentBuilds();
|
|
4764
|
+
else if (i.value === "lang") switchLocale(getLocale() === "fr" ? "en" : "fr");
|
|
3982
4765
|
else if (i.value === "logout") void logout();
|
|
3983
4766
|
else if (i.value === "uninstall") setPage({ name: "uninstall-confirm" });
|
|
3984
4767
|
else quit();
|
|
@@ -3991,9 +4774,9 @@ function App({
|
|
|
3991
4774
|
Keycaps,
|
|
3992
4775
|
{
|
|
3993
4776
|
items: [
|
|
3994
|
-
{ key: "\u2191\u2193", desc: "
|
|
3995
|
-
{ key: "tab", desc: "
|
|
3996
|
-
{ 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") }
|
|
3997
4780
|
]
|
|
3998
4781
|
}
|
|
3999
4782
|
) })
|
|
@@ -4008,17 +4791,17 @@ function App({
|
|
|
4008
4791
|
KeyValue,
|
|
4009
4792
|
{
|
|
4010
4793
|
rows: [
|
|
4011
|
-
["user", name || page2.me.email],
|
|
4012
|
-
["email", page2.me.email],
|
|
4013
|
-
["org", cfg.activeOrgName ? `${cfg.activeOrgName} (${cfg.activeOrgId})` : "
|
|
4014
|
-
["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"]
|
|
4015
4798
|
]
|
|
4016
4799
|
}
|
|
4017
4800
|
),
|
|
4018
4801
|
/* @__PURE__ */ jsx19(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx19(
|
|
4019
4802
|
SelectList,
|
|
4020
4803
|
{
|
|
4021
|
-
items: [backItem("
|
|
4804
|
+
items: [backItem(t("common.backToHome"))],
|
|
4022
4805
|
onSelect: () => back()
|
|
4023
4806
|
}
|
|
4024
4807
|
) })
|
|
@@ -4027,18 +4810,18 @@ function App({
|
|
|
4027
4810
|
}
|
|
4028
4811
|
case "quota": {
|
|
4029
4812
|
const rows2 = [
|
|
4030
|
-
["org", page2.orgName],
|
|
4031
|
-
["
|
|
4813
|
+
[t("whoami.row.org"), page2.orgName],
|
|
4814
|
+
[t("quota.row.remaining"), String(page2.remaining)]
|
|
4032
4815
|
];
|
|
4033
4816
|
if (page2.remaining === 0) {
|
|
4034
|
-
rows2.push(["note", "quota
|
|
4817
|
+
rows2.push([t("quota.row.note"), t("quota.exhausted")]);
|
|
4035
4818
|
}
|
|
4036
4819
|
body = /* @__PURE__ */ jsxs17(Box16, { flexDirection: "column", children: [
|
|
4037
4820
|
/* @__PURE__ */ jsx19(KeyValue, { rows: rows2 }),
|
|
4038
4821
|
/* @__PURE__ */ jsx19(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx19(
|
|
4039
4822
|
SelectList,
|
|
4040
4823
|
{
|
|
4041
|
-
items: [backItem("
|
|
4824
|
+
items: [backItem(t("common.backToHome"))],
|
|
4042
4825
|
onSelect: () => back()
|
|
4043
4826
|
}
|
|
4044
4827
|
) })
|
|
@@ -4050,8 +4833,8 @@ function App({
|
|
|
4050
4833
|
/* @__PURE__ */ jsx19(
|
|
4051
4834
|
TextField,
|
|
4052
4835
|
{
|
|
4053
|
-
title: "
|
|
4054
|
-
placeholder: "
|
|
4836
|
+
title: t("simulate.title"),
|
|
4837
|
+
placeholder: t("simulate.placeholder"),
|
|
4055
4838
|
onCancel: () => back(),
|
|
4056
4839
|
onSubmit: (task) => void startSimulation(task)
|
|
4057
4840
|
}
|
|
@@ -4060,10 +4843,10 @@ function App({
|
|
|
4060
4843
|
Keycaps,
|
|
4061
4844
|
{
|
|
4062
4845
|
items: [
|
|
4063
|
-
{ key: "enter", desc: "
|
|
4064
|
-
{ key: "\\ + enter", desc: "
|
|
4065
|
-
{ key: "\u2190\u2192\u2191\u2193", desc: "
|
|
4066
|
-
{ 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") }
|
|
4067
4850
|
]
|
|
4068
4851
|
}
|
|
4069
4852
|
) })
|
|
@@ -4071,21 +4854,21 @@ function App({
|
|
|
4071
4854
|
break;
|
|
4072
4855
|
case "job-source":
|
|
4073
4856
|
body = /* @__PURE__ */ jsxs17(Box16, { flexDirection: "column", children: [
|
|
4074
|
-
/* @__PURE__ */ jsx19(Box16, { marginBottom: 1, children: /* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc100, bold: true, children: "
|
|
4075
|
-
/* @__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") }),
|
|
4076
4859
|
/* @__PURE__ */ jsx19(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx19(
|
|
4077
4860
|
SelectList,
|
|
4078
4861
|
{
|
|
4079
4862
|
items: [
|
|
4080
4863
|
{
|
|
4081
|
-
label: "
|
|
4864
|
+
label: t("job.source.hf"),
|
|
4082
4865
|
value: "hf",
|
|
4083
|
-
hint:
|
|
4866
|
+
hint: t("job.source.hf.hint")
|
|
4084
4867
|
},
|
|
4085
4868
|
{
|
|
4086
|
-
label: "
|
|
4869
|
+
label: t("job.source.file"),
|
|
4087
4870
|
value: "file",
|
|
4088
|
-
hint: "
|
|
4871
|
+
hint: t("job.source.file.hint")
|
|
4089
4872
|
},
|
|
4090
4873
|
backItem()
|
|
4091
4874
|
],
|
|
@@ -4103,30 +4886,26 @@ function App({
|
|
|
4103
4886
|
/* @__PURE__ */ jsx19(
|
|
4104
4887
|
TextField,
|
|
4105
4888
|
{
|
|
4106
|
-
title: "
|
|
4107
|
-
placeholder: "
|
|
4889
|
+
title: t("job.hf.title"),
|
|
4890
|
+
placeholder: t("job.hf.placeholder"),
|
|
4108
4891
|
onCancel: () => back(),
|
|
4109
4892
|
onSubmit: (v) => void submitHfRepo(v)
|
|
4110
4893
|
}
|
|
4111
4894
|
),
|
|
4112
4895
|
hfTokenHint ? /* @__PURE__ */ jsxs17(Box16, { marginTop: 1, children: [
|
|
4113
|
-
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc600, children: "
|
|
4896
|
+
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc600, children: t("job.hf.tokenLabel") }),
|
|
4114
4897
|
hfTokenHint.account ? /* @__PURE__ */ jsxs17(Text19, { color: COLORS.emerald, children: [
|
|
4115
4898
|
hfTokenHint.account,
|
|
4116
4899
|
" "
|
|
4117
4900
|
] }) : null,
|
|
4118
|
-
/* @__PURE__ */
|
|
4119
|
-
|
|
4120
|
-
hfTokenHint.masked,
|
|
4121
|
-
")"
|
|
4122
|
-
] })
|
|
4123
|
-
] }) : /* @__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") }) }),
|
|
4124
4903
|
/* @__PURE__ */ jsx19(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx19(
|
|
4125
4904
|
Keycaps,
|
|
4126
4905
|
{
|
|
4127
4906
|
items: [
|
|
4128
|
-
{ key: "enter", desc: "
|
|
4129
|
-
{ key: "esc", desc: "
|
|
4907
|
+
{ key: "enter", desc: t("keycaps.checkAccess") },
|
|
4908
|
+
{ key: "esc", desc: t("keycaps.back") }
|
|
4130
4909
|
]
|
|
4131
4910
|
}
|
|
4132
4911
|
) })
|
|
@@ -4134,9 +4913,9 @@ function App({
|
|
|
4134
4913
|
break;
|
|
4135
4914
|
case "job-hf-confirm":
|
|
4136
4915
|
body = /* @__PURE__ */ jsxs17(Box16, { flexDirection: "column", children: [
|
|
4137
|
-
/* @__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") }) }),
|
|
4138
4917
|
/* @__PURE__ */ jsxs17(Text19, { children: [
|
|
4139
|
-
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc500, children: "repo
|
|
4918
|
+
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc500, children: t("job.hfConfirm.repo") }),
|
|
4140
4919
|
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc100, children: page2.repo }),
|
|
4141
4920
|
page2.revision ? /* @__PURE__ */ jsxs17(Text19, { color: COLORS.zinc500, children: [
|
|
4142
4921
|
" @ ",
|
|
@@ -4144,17 +4923,17 @@ function App({
|
|
|
4144
4923
|
] }) : null
|
|
4145
4924
|
] }),
|
|
4146
4925
|
/* @__PURE__ */ jsxs17(Text19, { children: [
|
|
4147
|
-
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc500, children: "
|
|
4148
|
-
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc100, children: page2.sizeBytes !== null ? formatBytes(page2.sizeBytes) : "
|
|
4149
|
-
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
|
|
4150
4929
|
] }),
|
|
4151
|
-
/* @__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") }) }),
|
|
4152
4931
|
/* @__PURE__ */ jsx19(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx19(
|
|
4153
4932
|
SelectList,
|
|
4154
4933
|
{
|
|
4155
4934
|
items: [
|
|
4156
|
-
{ label: "
|
|
4157
|
-
{ label: "
|
|
4935
|
+
{ label: t("job.hfConfirm.launch"), value: "go" },
|
|
4936
|
+
{ label: t("job.hfConfirm.editLink"), value: "edit" },
|
|
4158
4937
|
backItem()
|
|
4159
4938
|
],
|
|
4160
4939
|
onSelect: (i) => {
|
|
@@ -4171,8 +4950,8 @@ function App({
|
|
|
4171
4950
|
/* @__PURE__ */ jsx19(
|
|
4172
4951
|
TextField,
|
|
4173
4952
|
{
|
|
4174
|
-
title: "
|
|
4175
|
-
placeholder: "
|
|
4953
|
+
title: t("job.file.title"),
|
|
4954
|
+
placeholder: t("job.file.placeholder"),
|
|
4176
4955
|
onCancel: () => back(),
|
|
4177
4956
|
onSubmit: (v) => void submitFilePath(v)
|
|
4178
4957
|
}
|
|
@@ -4181,8 +4960,8 @@ function App({
|
|
|
4181
4960
|
Keycaps,
|
|
4182
4961
|
{
|
|
4183
4962
|
items: [
|
|
4184
|
-
{ key: "enter", desc: "
|
|
4185
|
-
{ key: "esc", desc: "
|
|
4963
|
+
{ key: "enter", desc: t("keycaps.validate") },
|
|
4964
|
+
{ key: "esc", desc: t("keycaps.back") }
|
|
4186
4965
|
]
|
|
4187
4966
|
}
|
|
4188
4967
|
) })
|
|
@@ -4190,9 +4969,9 @@ function App({
|
|
|
4190
4969
|
break;
|
|
4191
4970
|
case "job-file-confirm":
|
|
4192
4971
|
body = /* @__PURE__ */ jsxs17(Box16, { flexDirection: "column", children: [
|
|
4193
|
-
/* @__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") }) }),
|
|
4194
4973
|
/* @__PURE__ */ jsxs17(Text19, { children: [
|
|
4195
|
-
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc500, children: "
|
|
4974
|
+
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc500, children: t("job.fileConfirm.fileLabel") }),
|
|
4196
4975
|
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc100, children: page2.fileName }),
|
|
4197
4976
|
/* @__PURE__ */ jsxs17(Text19, { color: COLORS.zinc500, children: [
|
|
4198
4977
|
" (",
|
|
@@ -4201,15 +4980,15 @@ function App({
|
|
|
4201
4980
|
] })
|
|
4202
4981
|
] }),
|
|
4203
4982
|
/* @__PURE__ */ jsxs17(Box16, { marginTop: 1, flexDirection: "column", children: [
|
|
4204
|
-
/* @__PURE__ */ jsx19(Text19, { color: COLORS.amber, children: "
|
|
4205
|
-
/* @__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") })
|
|
4206
4985
|
] }),
|
|
4207
4986
|
/* @__PURE__ */ jsx19(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx19(
|
|
4208
4987
|
SelectList,
|
|
4209
4988
|
{
|
|
4210
4989
|
items: [
|
|
4211
|
-
{ label: "
|
|
4212
|
-
{ label: "
|
|
4990
|
+
{ label: t("job.fileConfirm.gotItLaunch"), value: "go" },
|
|
4991
|
+
{ label: t("job.fileConfirm.changeFile"), value: "edit" },
|
|
4213
4992
|
backItem()
|
|
4214
4993
|
],
|
|
4215
4994
|
onSelect: (i) => {
|
|
@@ -4235,7 +5014,7 @@ function App({
|
|
|
4235
5014
|
onDone: () => setPage({ name: "watch", buildId: page2.buildId }),
|
|
4236
5015
|
onError: (message) => setPage({
|
|
4237
5016
|
name: "error",
|
|
4238
|
-
title: "upload
|
|
5017
|
+
title: t("upload.interrupted.title"),
|
|
4239
5018
|
detail: message,
|
|
4240
5019
|
back: { name: "home" }
|
|
4241
5020
|
})
|
|
@@ -4262,20 +5041,20 @@ function App({
|
|
|
4262
5041
|
const active = !isTerminalStatus(page2.build.status);
|
|
4263
5042
|
const createdAtMs = page2.build.created_at ? Date.parse(page2.build.created_at) : void 0;
|
|
4264
5043
|
body = /* @__PURE__ */ jsxs17(Box16, { flexDirection: "column", children: [
|
|
4265
|
-
/* @__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") }) }),
|
|
4266
5045
|
/* @__PURE__ */ jsx19(JobSummary, { build: page2.build }),
|
|
4267
5046
|
/* @__PURE__ */ jsx19(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx19(
|
|
4268
5047
|
SelectList,
|
|
4269
5048
|
{
|
|
4270
5049
|
items: [
|
|
4271
5050
|
active ? {
|
|
4272
|
-
label: "
|
|
5051
|
+
label: t("buildSummary.watchLive"),
|
|
4273
5052
|
value: "rewatch",
|
|
4274
5053
|
labelColor: COLORS.emerald,
|
|
4275
5054
|
prefix: /* @__PURE__ */ jsx19(Twinkle, {})
|
|
4276
|
-
} : { label: "
|
|
4277
|
-
backItem("
|
|
4278
|
-
{ 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" }
|
|
4279
5058
|
],
|
|
4280
5059
|
onSelect: (i) => {
|
|
4281
5060
|
if (i.value === "rewatch")
|
|
@@ -4311,8 +5090,8 @@ function App({
|
|
|
4311
5090
|
SelectList,
|
|
4312
5091
|
{
|
|
4313
5092
|
items: [
|
|
4314
|
-
{ label: "
|
|
4315
|
-
{ label: "
|
|
5093
|
+
{ label: t("common.back"), value: "back", hint: t("common.orEscape") },
|
|
5094
|
+
{ label: t("common.quit"), value: "quit" }
|
|
4316
5095
|
],
|
|
4317
5096
|
onSelect: (i) => i.value === "back" ? setPage(page2.back) : quit()
|
|
4318
5097
|
}
|
|
@@ -4333,22 +5112,10 @@ function App({
|
|
|
4333
5112
|
justifyContent: "center",
|
|
4334
5113
|
flexDirection: "column",
|
|
4335
5114
|
children: [
|
|
4336
|
-
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc100, bold: true, children: "
|
|
5115
|
+
/* @__PURE__ */ jsx19(Text19, { color: COLORS.zinc100, bold: true, children: t("common.terminalTooSmall") }),
|
|
4337
5116
|
/* @__PURE__ */ jsxs17(Box16, { marginTop: 1, flexDirection: "column", alignItems: "center", children: [
|
|
4338
|
-
/* @__PURE__ */
|
|
4339
|
-
|
|
4340
|
-
MIN_COLS,
|
|
4341
|
-
"\xD7",
|
|
4342
|
-
MIN_ROWS,
|
|
4343
|
-
" minimum"
|
|
4344
|
-
] }),
|
|
4345
|
-
/* @__PURE__ */ jsxs17(Text19, { color: COLORS.zinc500, wrap: "truncate", children: [
|
|
4346
|
-
"(actuel : ",
|
|
4347
|
-
columns,
|
|
4348
|
-
"\xD7",
|
|
4349
|
-
rows,
|
|
4350
|
-
")"
|
|
4351
|
-
] })
|
|
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 }) })
|
|
4352
5119
|
] })
|
|
4353
5120
|
]
|
|
4354
5121
|
}
|
|
@@ -4640,8 +5407,8 @@ function Banner({ animate, onDone }) {
|
|
|
4640
5407
|
onDone?.();
|
|
4641
5408
|
return;
|
|
4642
5409
|
}
|
|
4643
|
-
const
|
|
4644
|
-
return () => clearTimeout(
|
|
5410
|
+
const t2 = setTimeout(() => setFrame((f) => f + 1), FRAME_MS3);
|
|
5411
|
+
return () => clearTimeout(t2);
|
|
4645
5412
|
}, [animate, frame, onDone]);
|
|
4646
5413
|
const color = colorEnabled();
|
|
4647
5414
|
const angle = 0.9 + frame * 0.05;
|
|
@@ -4651,7 +5418,8 @@ function Banner({ animate, onDone }) {
|
|
|
4651
5418
|
/* @__PURE__ */ jsx20(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx20(Text20, { children: planetFrame(angle, { orbitAngle }, color) }) }),
|
|
4652
5419
|
/* @__PURE__ */ jsx20(Box17, { marginTop: 1, children: /* @__PURE__ */ jsxs18(Text20, { color: COLORS.zinc500, children: [
|
|
4653
5420
|
/* @__PURE__ */ jsx20(Text20, { color: COLORS.emerald, children: "$" }),
|
|
4654
|
-
"
|
|
5421
|
+
" ",
|
|
5422
|
+
t("banner.tagline")
|
|
4655
5423
|
] }) })
|
|
4656
5424
|
] });
|
|
4657
5425
|
}
|
|
@@ -4660,23 +5428,20 @@ function Banner({ animate, onDone }) {
|
|
|
4660
5428
|
import { Box as Box18, Text as Text21 } from "ink";
|
|
4661
5429
|
import { jsx as jsx21, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
4662
5430
|
var COMMANDS = [
|
|
4663
|
-
{ cmd: "sumdae login", desc: "
|
|
4664
|
-
{ cmd: "sumdae whoami", desc: "
|
|
4665
|
-
{ cmd: "sumdae push <fichier>", desc: "
|
|
4666
|
-
{ cmd: "sumdae build <artifact>", desc: "
|
|
4667
|
-
{ cmd: "sumdae watch <buildId>", desc: "
|
|
4668
|
-
{ cmd: "sumdae cancel <buildId>", desc: "
|
|
4669
|
-
{ cmd: "sumdae quota", desc: "
|
|
4670
|
-
{ cmd: "sumdae org list", desc: "
|
|
4671
|
-
{ cmd: "sumdae org switch", desc: "
|
|
4672
|
-
{ 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") }
|
|
4673
5441
|
];
|
|
4674
5442
|
function Help({ version }) {
|
|
4675
5443
|
return /* @__PURE__ */ jsxs19(Box18, { flexDirection: "column", children: [
|
|
4676
|
-
/* @__PURE__ */
|
|
4677
|
-
"COMMANDES \xB7 v",
|
|
4678
|
-
version
|
|
4679
|
-
] }),
|
|
5444
|
+
/* @__PURE__ */ jsx21(Text21, { color: COLORS.zinc600, children: t("help.heading", { version }) }),
|
|
4680
5445
|
COMMANDS.map((c, i) => /* @__PURE__ */ jsxs19(Box18, { marginTop: i === 0 ? 1 : 0, children: [
|
|
4681
5446
|
/* @__PURE__ */ jsx21(Box18, { width: 9, children: /* @__PURE__ */ jsx21(Text21, { color: COLORS.zinc600, children: `cmd_${String(i + 1).padStart(2, "0")}` }) }),
|
|
4682
5447
|
/* @__PURE__ */ jsx21(Box18, { width: 22, children: /* @__PURE__ */ jsxs19(Text21, { color: COLORS.zinc100, children: [
|
|
@@ -4714,8 +5479,8 @@ async function homeAction(version) {
|
|
|
4714
5479
|
if (!interactive) {
|
|
4715
5480
|
const cfg2 = loadConfig();
|
|
4716
5481
|
const status = creds ? [
|
|
4717
|
-
creds.kind === "api-key" ? "
|
|
4718
|
-
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")
|
|
4719
5484
|
] : null;
|
|
4720
5485
|
const app2 = render3(/* @__PURE__ */ jsx22(Home, { animate: false, status, version }));
|
|
4721
5486
|
await app2.waitUntilExit();
|
|
@@ -4751,8 +5516,8 @@ var FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u282
|
|
|
4751
5516
|
function Spinner({ label }) {
|
|
4752
5517
|
const [i, setI] = useState11(0);
|
|
4753
5518
|
useEffect10(() => {
|
|
4754
|
-
const
|
|
4755
|
-
return () => clearInterval(
|
|
5519
|
+
const t2 = setInterval(() => setI((x) => (x + 1) % FRAMES.length), 80);
|
|
5520
|
+
return () => clearInterval(t2);
|
|
4756
5521
|
}, []);
|
|
4757
5522
|
return /* @__PURE__ */ jsxs21(Text23, { children: [
|
|
4758
5523
|
/* @__PURE__ */ jsx23(Text23, { color: COLORS.emerald, children: FRAMES[i] }),
|
|
@@ -4767,7 +5532,7 @@ function Spinner({ label }) {
|
|
|
4767
5532
|
import { jsx as jsx24, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
4768
5533
|
function orgItems(orgs, myId) {
|
|
4769
5534
|
return orgs.map((o) => {
|
|
4770
|
-
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");
|
|
4771
5536
|
return { label: o.name, value: o._id, hint: `${o.slug} \xB7 ${role}` };
|
|
4772
5537
|
});
|
|
4773
5538
|
}
|
|
@@ -4791,7 +5556,7 @@ function LoginApp({ noBrowser, skipAuth }) {
|
|
|
4791
5556
|
if (orgs.length === 0) {
|
|
4792
5557
|
setPhase({
|
|
4793
5558
|
step: "done",
|
|
4794
|
-
lines: [
|
|
5559
|
+
lines: [t("common.connectedAs", { email: me.email }), t("common.noOrgCreateOnLab")]
|
|
4795
5560
|
});
|
|
4796
5561
|
setTimeout(exit, 10);
|
|
4797
5562
|
return;
|
|
@@ -4799,7 +5564,7 @@ function LoginApp({ noBrowser, skipAuth }) {
|
|
|
4799
5564
|
if (!process.stdin.isTTY) {
|
|
4800
5565
|
setPhase({
|
|
4801
5566
|
step: "done",
|
|
4802
|
-
lines: [
|
|
5567
|
+
lines: [t("common.connectedAs", { email: me.email }), t("login.noOrgCreateThenSwitch")]
|
|
4803
5568
|
});
|
|
4804
5569
|
setTimeout(exit, 10);
|
|
4805
5570
|
return;
|
|
@@ -4810,7 +5575,7 @@ function LoginApp({ noBrowser, skipAuth }) {
|
|
|
4810
5575
|
process.exitCode = 1;
|
|
4811
5576
|
setPhase({
|
|
4812
5577
|
step: "error",
|
|
4813
|
-
title: "
|
|
5578
|
+
title: t("common.loginFailed"),
|
|
4814
5579
|
detail: e instanceof Error ? e.message : String(e)
|
|
4815
5580
|
});
|
|
4816
5581
|
setTimeout(exit, 10);
|
|
@@ -4819,21 +5584,18 @@ function LoginApp({ noBrowser, skipAuth }) {
|
|
|
4819
5584
|
}, []);
|
|
4820
5585
|
if (phase.step === "auth") {
|
|
4821
5586
|
return /* @__PURE__ */ jsxs22(Box20, { flexDirection: "column", children: [
|
|
4822
|
-
/* @__PURE__ */ jsx24(Spinner, { label: "
|
|
5587
|
+
/* @__PURE__ */ jsx24(Spinner, { label: t("common.waitingBrowserLogin") }),
|
|
4823
5588
|
noBrowser && authorizeUrl ? /* @__PURE__ */ jsxs22(Box20, { marginTop: 1, flexDirection: "column", children: [
|
|
4824
|
-
/* @__PURE__ */ jsx24(Text24, { color: COLORS.zinc500, children: "
|
|
5589
|
+
/* @__PURE__ */ jsx24(Text24, { color: COLORS.zinc500, children: t("login.browser.openUrl") }),
|
|
4825
5590
|
/* @__PURE__ */ jsx24(Text24, { color: COLORS.emerald, children: authorizeUrl })
|
|
4826
5591
|
] }) : null
|
|
4827
5592
|
] });
|
|
4828
5593
|
}
|
|
4829
5594
|
if (phase.step === "orgs") {
|
|
4830
5595
|
return /* @__PURE__ */ jsxs22(Box20, { flexDirection: "column", children: [
|
|
4831
|
-
/* @__PURE__ */
|
|
4832
|
-
"connect\xE9 : ",
|
|
4833
|
-
/* @__PURE__ */ jsx24(Text24, { color: COLORS.zinc100, children: phase.me.email })
|
|
4834
|
-
] }),
|
|
5596
|
+
/* @__PURE__ */ jsx24(Text24, { color: COLORS.zinc400, children: t("common.connectedAs", { email: phase.me.email }) }),
|
|
4835
5597
|
/* @__PURE__ */ jsxs22(Box20, { marginTop: 1, flexDirection: "column", children: [
|
|
4836
|
-
/* @__PURE__ */ jsx24(Text24, { color: COLORS.zinc500, children: "
|
|
5598
|
+
/* @__PURE__ */ jsx24(Text24, { color: COLORS.zinc500, children: t("common.activeOrgLabel") }),
|
|
4837
5599
|
/* @__PURE__ */ jsx24(
|
|
4838
5600
|
SelectList,
|
|
4839
5601
|
{
|
|
@@ -4842,7 +5604,7 @@ function LoginApp({ noBrowser, skipAuth }) {
|
|
|
4842
5604
|
const org2 = phase.orgs.find((o) => o._id === item.value);
|
|
4843
5605
|
if (!org2) return;
|
|
4844
5606
|
saveActiveOrg(org2);
|
|
4845
|
-
setPhase({ step: "done", lines: [
|
|
5607
|
+
setPhase({ step: "done", lines: [t("common.activeOrgSet", { name: org2.name })] });
|
|
4846
5608
|
setTimeout(exit, 10);
|
|
4847
5609
|
}
|
|
4848
5610
|
}
|
|
@@ -4860,10 +5622,10 @@ async function loginAction(opts) {
|
|
|
4860
5622
|
if (opts.withKey) {
|
|
4861
5623
|
const { createInterface } = await import("readline/promises");
|
|
4862
5624
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
4863
|
-
const key = (await rl.question(
|
|
5625
|
+
const key = (await rl.question(t("login.key.prompt"))).trim();
|
|
4864
5626
|
rl.close();
|
|
4865
5627
|
if (!key) {
|
|
4866
|
-
console.error("
|
|
5628
|
+
console.error(t("login.noKeyProvided"));
|
|
4867
5629
|
process.exitCode = 1;
|
|
4868
5630
|
return;
|
|
4869
5631
|
}
|
|
@@ -4874,7 +5636,7 @@ async function loginAction(opts) {
|
|
|
4874
5636
|
}
|
|
4875
5637
|
if (!process.stdout.isTTY) {
|
|
4876
5638
|
console.error(
|
|
4877
|
-
"
|
|
5639
|
+
t("login.nonInteractiveTty")
|
|
4878
5640
|
);
|
|
4879
5641
|
process.exitCode = 1;
|
|
4880
5642
|
return;
|
|
@@ -4890,7 +5652,7 @@ async function logoutAction() {
|
|
|
4890
5652
|
delete cfg.activeOrgId;
|
|
4891
5653
|
delete cfg.activeOrgName;
|
|
4892
5654
|
saveConfig(cfg);
|
|
4893
|
-
console.log(ok("
|
|
5655
|
+
console.log(ok(t("logout.done")));
|
|
4894
5656
|
}
|
|
4895
5657
|
|
|
4896
5658
|
// src/commands/org.tsx
|
|
@@ -4906,7 +5668,7 @@ async function fetchOrgItems() {
|
|
|
4906
5668
|
items: orgs.map((o) => ({
|
|
4907
5669
|
label: o.name,
|
|
4908
5670
|
value: o._id,
|
|
4909
|
-
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")}`
|
|
4910
5672
|
}))
|
|
4911
5673
|
};
|
|
4912
5674
|
}
|
|
@@ -4914,7 +5676,7 @@ async function orgListAction() {
|
|
|
4914
5676
|
try {
|
|
4915
5677
|
const { items } = await fetchOrgItems();
|
|
4916
5678
|
if (items.length === 0) {
|
|
4917
|
-
console.log("
|
|
5679
|
+
console.log(t("common.noOrgCreateOnLab"));
|
|
4918
5680
|
return;
|
|
4919
5681
|
}
|
|
4920
5682
|
const active = loadConfig().activeOrgId;
|
|
@@ -4937,14 +5699,11 @@ function SwitchApp({ items, orgs }) {
|
|
|
4937
5699
|
if (picked) {
|
|
4938
5700
|
return /* @__PURE__ */ jsxs23(Text25, { children: [
|
|
4939
5701
|
/* @__PURE__ */ jsx25(Text25, { color: COLORS.emerald, children: "\u2713 " }),
|
|
4940
|
-
/* @__PURE__ */
|
|
4941
|
-
"organisation active : ",
|
|
4942
|
-
picked.label
|
|
4943
|
-
] })
|
|
5702
|
+
/* @__PURE__ */ jsx25(Text25, { color: COLORS.zinc100, children: t("common.activeOrgSet", { name: picked.label }) })
|
|
4944
5703
|
] });
|
|
4945
5704
|
}
|
|
4946
5705
|
return /* @__PURE__ */ jsxs23(Box21, { flexDirection: "column", children: [
|
|
4947
|
-
/* @__PURE__ */ jsx25(Text25, { color: COLORS.zinc500, children: "
|
|
5706
|
+
/* @__PURE__ */ jsx25(Text25, { color: COLORS.zinc500, children: t("common.activeOrgLabel") }),
|
|
4948
5707
|
/* @__PURE__ */ jsx25(
|
|
4949
5708
|
SelectList,
|
|
4950
5709
|
{
|
|
@@ -4964,11 +5723,11 @@ async function orgSwitchAction() {
|
|
|
4964
5723
|
try {
|
|
4965
5724
|
const { items, orgs } = await fetchOrgItems();
|
|
4966
5725
|
if (items.length === 0) {
|
|
4967
|
-
console.log("
|
|
5726
|
+
console.log(t("common.noOrgCreateOnLab"));
|
|
4968
5727
|
return;
|
|
4969
5728
|
}
|
|
4970
5729
|
if (!process.stdin.isTTY) {
|
|
4971
|
-
console.error("
|
|
5730
|
+
console.error(t("orgs.nonInteractiveTty"));
|
|
4972
5731
|
process.exitCode = 1;
|
|
4973
5732
|
return;
|
|
4974
5733
|
}
|
|
@@ -4996,7 +5755,7 @@ async function hashFile(path, signal) {
|
|
|
4996
5755
|
for await (const chunk of stream) {
|
|
4997
5756
|
if (signal?.aborted) {
|
|
4998
5757
|
stream.destroy();
|
|
4999
|
-
throw new Error("upload
|
|
5758
|
+
throw new Error(t("upload.err.cancelled"));
|
|
5000
5759
|
}
|
|
5001
5760
|
hash.update(chunk);
|
|
5002
5761
|
}
|
|
@@ -5028,7 +5787,7 @@ var PartUrlProvider = class {
|
|
|
5028
5787
|
if (url) return url;
|
|
5029
5788
|
await this.fetchBatch(partNumber);
|
|
5030
5789
|
const retry = this.cache.get(partNumber);
|
|
5031
|
-
if (!retry) throw new Error(
|
|
5790
|
+
if (!retry) throw new Error(t("upload.err.missingPresigned", { n: partNumber }));
|
|
5032
5791
|
return retry;
|
|
5033
5792
|
}
|
|
5034
5793
|
async fetchBatch(from) {
|
|
@@ -5089,7 +5848,7 @@ async function pushArtifact(opts) {
|
|
|
5089
5848
|
const partNumber = next;
|
|
5090
5849
|
if (partNumber > partsTotal) return;
|
|
5091
5850
|
next += 1;
|
|
5092
|
-
if (signal?.aborted) throw new Error("upload
|
|
5851
|
+
if (signal?.aborted) throw new Error(t("upload.err.cancelled"));
|
|
5093
5852
|
const offset = (partNumber - 1) * partSize;
|
|
5094
5853
|
const length = Math.min(partSize, totalBytes - offset);
|
|
5095
5854
|
const buf = Buffer.alloc(length);
|
|
@@ -5101,7 +5860,7 @@ async function pushArtifact(opts) {
|
|
|
5101
5860
|
const res = await fetch(url, { method: "PUT", body: buf, signal });
|
|
5102
5861
|
if (!res.ok) throw new Error(`R2 HTTP ${res.status}`);
|
|
5103
5862
|
const etag = res.headers.get("etag");
|
|
5104
|
-
if (!etag) throw new Error("
|
|
5863
|
+
if (!etag) throw new Error(t("upload.err.missingEtag"));
|
|
5105
5864
|
etags.set(partNumber, etag);
|
|
5106
5865
|
sentBytes += length;
|
|
5107
5866
|
partsDone += 1;
|
|
@@ -5110,13 +5869,18 @@ async function pushArtifact(opts) {
|
|
|
5110
5869
|
break;
|
|
5111
5870
|
} catch (e) {
|
|
5112
5871
|
lastErr = e;
|
|
5113
|
-
if (signal?.aborted) throw new Error("upload
|
|
5872
|
+
if (signal?.aborted) throw new Error(t("upload.err.cancelled"));
|
|
5114
5873
|
if (attempt < maxRetries) await sleep(300 * attempt);
|
|
5115
5874
|
}
|
|
5116
5875
|
}
|
|
5117
5876
|
if (lastErr) {
|
|
5118
5877
|
throw new Error(
|
|
5119
|
-
|
|
5878
|
+
t("upload.err.partFailed", {
|
|
5879
|
+
n: partNumber,
|
|
5880
|
+
total: partsTotal,
|
|
5881
|
+
tries: maxRetries,
|
|
5882
|
+
msg: lastErr instanceof Error ? lastErr.message : String(lastErr)
|
|
5883
|
+
})
|
|
5120
5884
|
);
|
|
5121
5885
|
}
|
|
5122
5886
|
}
|
|
@@ -5221,11 +5985,11 @@ function PushApp({
|
|
|
5221
5985
|
)
|
|
5222
5986
|
] });
|
|
5223
5987
|
}
|
|
5224
|
-
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 });
|
|
5225
5989
|
return /* @__PURE__ */ jsxs24(Box22, { flexDirection: "column", children: [
|
|
5226
5990
|
/* @__PURE__ */ jsxs24(Text26, { children: [
|
|
5227
5991
|
/* @__PURE__ */ jsx26(Text26, { color: COLORS.emerald, children: "\u2713 " }),
|
|
5228
|
-
/* @__PURE__ */ jsx26(Text26, { color: COLORS.zinc100, children: "
|
|
5992
|
+
/* @__PURE__ */ jsx26(Text26, { color: COLORS.zinc100, children: t("push.uploaded") })
|
|
5229
5993
|
] }),
|
|
5230
5994
|
/* @__PURE__ */ jsxs24(Text26, { color: COLORS.zinc500, children: [
|
|
5231
5995
|
"id ",
|
|
@@ -5243,14 +6007,14 @@ async function pushAction(filePath2, opts) {
|
|
|
5243
6007
|
const kind = opts.kind ?? inferKind(filePath2);
|
|
5244
6008
|
if (kind !== "weights" && kind !== "pipeline") {
|
|
5245
6009
|
console.error(
|
|
5246
|
-
"
|
|
6010
|
+
t("push.inferKindFailed")
|
|
5247
6011
|
);
|
|
5248
6012
|
process.exitCode = 1;
|
|
5249
6013
|
return;
|
|
5250
6014
|
}
|
|
5251
6015
|
const active = await resolveActiveOrg().catch(() => null);
|
|
5252
6016
|
if (!active) {
|
|
5253
|
-
console.error("
|
|
6017
|
+
console.error(t("common.noActiveOrgRunSwitch"));
|
|
5254
6018
|
process.exitCode = 1;
|
|
5255
6019
|
return;
|
|
5256
6020
|
}
|
|
@@ -5267,17 +6031,17 @@ async function quotaAction() {
|
|
|
5267
6031
|
try {
|
|
5268
6032
|
const active = await resolveActiveOrg();
|
|
5269
6033
|
if (!active) {
|
|
5270
|
-
console.error("
|
|
6034
|
+
console.error(t("common.noActiveOrgRunSwitch"));
|
|
5271
6035
|
process.exitCode = 1;
|
|
5272
6036
|
return;
|
|
5273
6037
|
}
|
|
5274
6038
|
const q = await getOrgQuota(active.slug);
|
|
5275
6039
|
const rows = [
|
|
5276
|
-
["org", `${active.name} (${active.slug})`],
|
|
5277
|
-
["
|
|
6040
|
+
[t("whoami.row.org"), `${active.name} (${active.slug})`],
|
|
6041
|
+
[t("quota.row.remaining"), String(q.remaining)]
|
|
5278
6042
|
];
|
|
5279
6043
|
if (q.remaining === 0) {
|
|
5280
|
-
rows.push(["note", "quota
|
|
6044
|
+
rows.push([t("quota.row.note"), t("quota.exhausted")]);
|
|
5281
6045
|
}
|
|
5282
6046
|
render7(/* @__PURE__ */ jsx27(KeyValue, { rows }));
|
|
5283
6047
|
} catch (e) {
|
|
@@ -5288,10 +6052,10 @@ async function quotaAction() {
|
|
|
5288
6052
|
|
|
5289
6053
|
// src/commands/uninstall.ts
|
|
5290
6054
|
function printPlan(plan) {
|
|
5291
|
-
console.log("
|
|
6055
|
+
console.log(t("uninstall.cli.heading"));
|
|
5292
6056
|
console.log(` canal : ${plan.channel}`);
|
|
5293
6057
|
if (plan.channel === "npm") {
|
|
5294
|
-
console.log(
|
|
6058
|
+
console.log(` install : ${plan.manualHint ?? t("uninstall.cli.installGlobal")}`);
|
|
5295
6059
|
} else if (plan.installBlockedReason) {
|
|
5296
6060
|
console.log(` install : manuel \u2192 ${plan.manualHint ?? plan.installRoot}`);
|
|
5297
6061
|
} else {
|
|
@@ -5299,14 +6063,14 @@ function printPlan(plan) {
|
|
|
5299
6063
|
if (plan.launcherPath) console.log(` launcher : ${plan.launcherPath}`);
|
|
5300
6064
|
}
|
|
5301
6065
|
console.log(` config : ${plan.configDir}`);
|
|
5302
|
-
console.log("
|
|
6066
|
+
console.log(t("uninstall.cli.credentials"));
|
|
5303
6067
|
}
|
|
5304
6068
|
async function uninstallAction(opts = {}) {
|
|
5305
6069
|
const interactive = process.stdout.isTTY === true && process.stdin.isTTY === true;
|
|
5306
6070
|
if (interactive && !opts.yes) {
|
|
5307
6071
|
const report2 = await runUninstallScreen();
|
|
5308
6072
|
if (!report2) {
|
|
5309
|
-
console.log("
|
|
6073
|
+
console.log(t("uninstall.cli.cancelled"));
|
|
5310
6074
|
return;
|
|
5311
6075
|
}
|
|
5312
6076
|
if (report2.some((s) => s.step !== "install" && !s.ok)) process.exitCode = 1;
|
|
@@ -5320,13 +6084,13 @@ async function uninstallAction(opts = {}) {
|
|
|
5320
6084
|
if (s.ok) {
|
|
5321
6085
|
console.log(ok(s.step));
|
|
5322
6086
|
} else if (s.step === "install") {
|
|
5323
|
-
console.log(warn(`${s.step} \u2014 ${s.error ?? "
|
|
6087
|
+
console.log(warn(`${s.step} \u2014 ${s.error ?? t("uninstall.cli.manualFallback")}`));
|
|
5324
6088
|
} else {
|
|
5325
|
-
console.log(ko(`${s.step} \u2014 ${s.error ?? "
|
|
6089
|
+
console.log(ko(`${s.step} \u2014 ${s.error ?? t("uninstall.cli.stepFailed")}`));
|
|
5326
6090
|
dataFailed = true;
|
|
5327
6091
|
}
|
|
5328
6092
|
}
|
|
5329
|
-
console.log("
|
|
6093
|
+
console.log(t("uninstall.cli.cleaned"));
|
|
5330
6094
|
if (dataFailed) process.exitCode = 1;
|
|
5331
6095
|
}
|
|
5332
6096
|
|
|
@@ -5335,7 +6099,7 @@ import { render as render8 } from "ink";
|
|
|
5335
6099
|
import { jsx as jsx28 } from "react/jsx-runtime";
|
|
5336
6100
|
function machineLine() {
|
|
5337
6101
|
const s = getSystemInfo();
|
|
5338
|
-
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)}`;
|
|
5339
6103
|
}
|
|
5340
6104
|
async function whoamiAction() {
|
|
5341
6105
|
try {
|
|
@@ -5343,17 +6107,19 @@ async function whoamiAction() {
|
|
|
5343
6107
|
const cfg = loadConfig();
|
|
5344
6108
|
const creds = await loadCredentials();
|
|
5345
6109
|
const name = `${me.first_name} ${me.last_name}`.trim();
|
|
5346
|
-
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
|
+
});
|
|
5347
6113
|
render8(
|
|
5348
6114
|
/* @__PURE__ */ jsx28(
|
|
5349
6115
|
KeyValue,
|
|
5350
6116
|
{
|
|
5351
6117
|
rows: [
|
|
5352
|
-
["user", name || me.email],
|
|
5353
|
-
["email", me.email],
|
|
5354
|
-
["org", cfg.activeOrgName ? `${cfg.activeOrgName} (${cfg.activeOrgId})` : "
|
|
5355
|
-
["session", session],
|
|
5356
|
-
["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()]
|
|
5357
6123
|
]
|
|
5358
6124
|
}
|
|
5359
6125
|
)
|
|
@@ -5390,7 +6156,7 @@ function UpdateApp({
|
|
|
5390
6156
|
if (channel === "npm") {
|
|
5391
6157
|
setPhase({ kind: "install" });
|
|
5392
6158
|
const ok2 = updateViaNpm(latest.version);
|
|
5393
|
-
if (!ok2) throw new Error("
|
|
6159
|
+
if (!ok2) throw new Error(t("update.err.npmFailed"));
|
|
5394
6160
|
setPhase({ kind: "done" });
|
|
5395
6161
|
setTimeout(() => relaunch(), 300);
|
|
5396
6162
|
return;
|
|
@@ -5398,10 +6164,10 @@ function UpdateApp({
|
|
|
5398
6164
|
const { path, sha256 } = await downloadTarball(latest.tarball_url, (done, total) => {
|
|
5399
6165
|
if (alive) setPhase({ kind: "download", done, total: total || latest.size });
|
|
5400
6166
|
});
|
|
5401
|
-
if (sha256 !== latest.sha256) throw new Error("
|
|
6167
|
+
if (sha256 !== latest.sha256) throw new Error(t("update.err.sha256Mismatch"));
|
|
5402
6168
|
setPhase({ kind: "verify" });
|
|
5403
6169
|
if (!verifyTarball(path, latest.signature)) {
|
|
5404
|
-
throw new Error("
|
|
6170
|
+
throw new Error(t("update.err.invalidSignature"));
|
|
5405
6171
|
}
|
|
5406
6172
|
setPhase({ kind: "install" });
|
|
5407
6173
|
installTarball(path);
|
|
@@ -5435,17 +6201,17 @@ function UpdateApp({
|
|
|
5435
6201
|
suffix: phase.total ? `${fmtBytes3(phase.done)} / ${fmtBytes3(phase.total)}` : fmtBytes3(phase.done)
|
|
5436
6202
|
}
|
|
5437
6203
|
),
|
|
5438
|
-
/* @__PURE__ */ jsx29(Text27, { color: COLORS.zinc500, children:
|
|
6204
|
+
/* @__PURE__ */ jsx29(Text27, { color: COLORS.zinc500, children: t("update.downloading") })
|
|
5439
6205
|
] });
|
|
5440
6206
|
case "verify":
|
|
5441
|
-
return /* @__PURE__ */ jsx29(Text27, { color: COLORS.zinc400, children: "
|
|
6207
|
+
return /* @__PURE__ */ jsx29(Text27, { color: COLORS.zinc400, children: t("update.verifyingSignature") });
|
|
5442
6208
|
case "install":
|
|
5443
|
-
return /* @__PURE__ */ jsx29(Text27, { color: COLORS.zinc400, children: "
|
|
6209
|
+
return /* @__PURE__ */ jsx29(Text27, { color: COLORS.zinc400, children: t("update.installing") });
|
|
5444
6210
|
case "done":
|
|
5445
|
-
return /* @__PURE__ */ jsx29(Text27, { color: COLORS.emerald, children: "
|
|
6211
|
+
return /* @__PURE__ */ jsx29(Text27, { color: COLORS.emerald, children: t("update.doneRestarting") });
|
|
5446
6212
|
case "error":
|
|
5447
6213
|
return /* @__PURE__ */ jsxs25(Fragment3, { children: [
|
|
5448
|
-
/* @__PURE__ */ jsx29(Text27, { color: COLORS.red, children: "
|
|
6214
|
+
/* @__PURE__ */ jsx29(Text27, { color: COLORS.red, children: t("update.failed") }),
|
|
5449
6215
|
/* @__PURE__ */ jsx29(Text27, { color: COLORS.zinc500, wrap: "truncate", children: phase.message })
|
|
5450
6216
|
] });
|
|
5451
6217
|
}
|
|
@@ -5459,7 +6225,7 @@ function UpdateApp({
|
|
|
5459
6225
|
justifyContent: "center",
|
|
5460
6226
|
flexDirection: "column",
|
|
5461
6227
|
children: [
|
|
5462
|
-
/* @__PURE__ */ jsx29(Text27, { color: COLORS.zinc100, bold: true, children: "
|
|
6228
|
+
/* @__PURE__ */ jsx29(Text27, { color: COLORS.zinc100, bold: true, children: t("update.screen.title") }),
|
|
5463
6229
|
/* @__PURE__ */ jsx29(Box23, { marginTop: 1, marginBottom: 1, children: /* @__PURE__ */ jsxs25(Text27, { color: COLORS.zinc500, children: [
|
|
5464
6230
|
"v",
|
|
5465
6231
|
current,
|
|
@@ -5500,35 +6266,34 @@ async function maybeSelfUpdate(argv) {
|
|
|
5500
6266
|
const err = await runUpdateScreen(decision.latest, decision.current);
|
|
5501
6267
|
if (err && decision.forced) {
|
|
5502
6268
|
console.error(
|
|
5503
|
-
|
|
5504
|
-
R\xE9essayez, ou r\xE9installez : https://lab.sumdae.fr/cli`
|
|
6269
|
+
t("update.forcedFailed", { current: decision.current, err })
|
|
5505
6270
|
);
|
|
5506
6271
|
process.exit(1);
|
|
5507
6272
|
}
|
|
5508
6273
|
}
|
|
5509
6274
|
await maybeSelfUpdate(process.argv);
|
|
5510
6275
|
var program = new Command();
|
|
5511
|
-
program.name("sumdae").description("
|
|
6276
|
+
program.name("sumdae").description(t("cli.root.description")).version(CLI_VERSION).action(async () => {
|
|
5512
6277
|
await homeAction(CLI_VERSION);
|
|
5513
6278
|
});
|
|
5514
|
-
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) => {
|
|
5515
6280
|
await loginAction({ noBrowser: !opts.browser, withKey: opts.withKey });
|
|
5516
6281
|
});
|
|
5517
|
-
program.command("logout").description("
|
|
5518
|
-
program.command("whoami").description("
|
|
5519
|
-
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) => {
|
|
5520
6285
|
await uninstallAction({ yes: opts.yes });
|
|
5521
6286
|
});
|
|
5522
|
-
program.command("quota").description("
|
|
5523
|
-
program.command("push <fichier>").description("
|
|
5524
|
-
program.command("build <weightsArtifactId>").description("
|
|
5525
|
-
program.command("simulate <task...>").description(
|
|
5526
|
-
program.command("watch <buildId>").description(
|
|
5527
|
-
program.command("cancel <buildId>").description(
|
|
5528
|
-
var agent = program.command("agent").description("
|
|
5529
|
-
agent.command("kill <buildId>").description("
|
|
5530
|
-
agent.command("msg <buildId> <message>").description("
|
|
5531
|
-
var org = program.command("org").description("
|
|
5532
|
-
org.command("list").description("
|
|
5533
|
-
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);
|
|
5534
6299
|
await program.parseAsync();
|