@elding/cli 0.2.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/dist/commands/doctor.d.ts +1 -0
  2. package/dist/commands/doctor.js +58 -0
  3. package/dist/commands/init.js +29 -5
  4. package/dist/commands/keys.d.ts +1 -0
  5. package/dist/commands/keys.js +31 -0
  6. package/dist/commands/login.js +40 -25
  7. package/dist/commands/open.d.ts +1 -0
  8. package/dist/commands/open.js +13 -0
  9. package/dist/commands/proxy.d.ts +6 -1
  10. package/dist/commands/proxy.js +23 -7
  11. package/dist/commands/run.d.ts +4 -1
  12. package/dist/commands/run.js +17 -6
  13. package/dist/commands/sets.d.ts +1 -0
  14. package/dist/commands/sets.js +26 -0
  15. package/dist/commands/status.js +3 -2
  16. package/dist/commands/use.d.ts +1 -0
  17. package/dist/commands/use.js +37 -0
  18. package/dist/commands/whoami.d.ts +1 -0
  19. package/dist/commands/whoami.js +12 -0
  20. package/dist/index.js +75 -9
  21. package/dist/lib/api.d.ts +11 -1
  22. package/dist/lib/api.js +65 -20
  23. package/dist/lib/apiUrl.d.ts +1 -0
  24. package/dist/lib/apiUrl.js +44 -0
  25. package/dist/lib/config.d.ts +11 -0
  26. package/dist/lib/config.js +100 -7
  27. package/dist/lib/env.d.ts +5 -0
  28. package/dist/lib/env.js +49 -0
  29. package/dist/lib/keychain.d.ts +3 -0
  30. package/dist/lib/keychain.js +39 -0
  31. package/dist/lib/logBatcher.d.ts +5 -0
  32. package/dist/lib/logBatcher.js +42 -0
  33. package/dist/lib/proxyServer.d.ts +10 -1
  34. package/dist/lib/proxyServer.js +219 -48
  35. package/dist/lib/session.d.ts +1 -0
  36. package/dist/lib/session.js +17 -0
  37. package/dist/lib/terminal.d.ts +2 -0
  38. package/dist/lib/terminal.js +15 -0
  39. package/dist/lib/trust.d.ts +2 -0
  40. package/dist/lib/trust.js +33 -0
  41. package/package.json +11 -10
@@ -0,0 +1 @@
1
+ export declare function doctor(): Promise<void>;
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.doctor = doctor;
4
+ const config_js_1 = require("../lib/config.js");
5
+ const api_js_1 = require("../lib/api.js");
6
+ const terminal_js_1 = require("../lib/terminal.js");
7
+ async function doctor() {
8
+ const { default: chalk } = await import("chalk");
9
+ const ok = (m) => console.log(`${chalk.green("✓")} ${m}`);
10
+ const warn = (m) => console.log(`${chalk.yellow("!")} ${m}`);
11
+ const fail = (m) => console.log(`${chalk.red("✗")} ${m}`);
12
+ console.log(chalk.dim(`API : ${api_js_1.BASE_URL}\n`));
13
+ // 1. Token local
14
+ const config = (0, config_js_1.readConfig)();
15
+ if (!config) {
16
+ fail("Non connecté — lancez `elding login`");
17
+ return;
18
+ }
19
+ ok("Token local présent (trousseau OS)");
20
+ // 2. Token valide + utilisateur
21
+ let accessToken;
22
+ try {
23
+ accessToken = await (0, api_js_1.exchangeToken)(config.refreshToken);
24
+ const me = await (0, api_js_1.getMe)(accessToken);
25
+ ok(`Authentifié : ${(0, terminal_js_1.safeText)(me.email)}`);
26
+ }
27
+ catch {
28
+ fail("Token expiré ou révoqué — relancez `elding login`");
29
+ return;
30
+ }
31
+ // 3. Set du projet
32
+ const project = (0, config_js_1.readProject)();
33
+ if (!project) {
34
+ warn("Aucun set configuré — lancez `elding init` ou `elding use <set>`");
35
+ return;
36
+ }
37
+ ok(`Set actif : ${(0, terminal_js_1.safeText)(project.setName)}`);
38
+ // 4. Clés + verrouillage host
39
+ try {
40
+ const keys = await (0, api_js_1.listKeys)(accessToken, project.setId);
41
+ if (keys.length === 0)
42
+ warn("Le set ne contient aucune clé");
43
+ else {
44
+ const locked = keys.filter((k) => k.allowedHost).length;
45
+ ok(`${keys.length} clé(s) — ${locked} verrouillée(s) sur un domaine`);
46
+ if (locked < keys.length)
47
+ warn(`${keys.length - locked} clé(s) sans domaine : exfiltrables via le proxy`);
48
+ }
49
+ }
50
+ catch {
51
+ fail("Impossible de lire les clés du set");
52
+ }
53
+ // 5. Proxy
54
+ if (process.env.ELDING_PROXY_URL)
55
+ ok(`Proxy actif : ${process.env.ELDING_PROXY_URL}`);
56
+ else
57
+ console.log(chalk.dim("○ Proxy inactif (normal hors `elding proxy`)"));
58
+ }
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.init = init;
4
4
  const config_js_1 = require("../lib/config.js");
5
5
  const api_js_1 = require("../lib/api.js");
6
+ const terminal_js_1 = require("../lib/terminal.js");
6
7
  async function init() {
7
8
  const { default: chalk } = await import("chalk");
8
9
  const { default: ora } = await import("ora");
@@ -31,19 +32,42 @@ async function init() {
31
32
  process.exit(1);
32
33
  }
33
34
  if (sets.length === 0) {
34
- console.log(chalk.yellow("Aucun set trouvé. Créez-en un sur app.elding.io."));
35
+ console.log(chalk.yellow("Aucun set trouvé. Créez-en un sur le vault."));
35
36
  process.exit(0);
36
37
  }
38
+ // Étape 1 : choisir l'organisation (sauf s'il n'y en a qu'une)
39
+ const orgs = [...new Map(sets.map((s) => [s.workspaceId, s.workspaceName])).entries()];
40
+ let workspaceId = orgs[0][0];
41
+ if (orgs.length > 1) {
42
+ const ans = await inquirer.prompt([
43
+ {
44
+ type: "list",
45
+ name: "workspaceId",
46
+ message: "Quelle organisation ?",
47
+ choices: orgs.map(([id, name]) => ({ name: (0, terminal_js_1.safeText)(name), value: id })),
48
+ },
49
+ ]);
50
+ workspaceId = ans.workspaceId;
51
+ }
52
+ // Étape 2 : choisir le set parmi ceux de l'org
53
+ const orgSets = sets.filter((s) => s.workspaceId === workspaceId);
37
54
  const { setId } = await inquirer.prompt([
38
55
  {
39
56
  type: "list",
40
57
  name: "setId",
41
58
  message: "Quel set utiliser pour ce projet ?",
42
- choices: sets.map((s) => ({ name: s.name, value: s.id })),
59
+ choices: orgSets.map((s) => ({ name: (0, terminal_js_1.safeText)(s.name), value: s.id })),
43
60
  },
44
61
  ]);
45
- const selected = sets.find((s) => s.id === setId);
46
- (0, config_js_1.writeProject)({ setId: selected.id, setName: selected.name });
47
- console.log(chalk.green(`✓ Set "${selected.name}" configuré dans .elding.json`));
62
+ const selected = orgSets.find((s) => s.id === setId);
63
+ const project = {
64
+ setId: selected.id,
65
+ setName: selected.name,
66
+ workspaceId: selected.workspaceId,
67
+ workspaceName: selected.workspaceName,
68
+ };
69
+ (0, config_js_1.writeProject)(project);
70
+ (0, config_js_1.trustProject)(project);
71
+ console.log(chalk.green(`✓ Set "${(0, terminal_js_1.safeText)(selected.name)}" (${(0, terminal_js_1.safeText)(selected.workspaceName)}) configuré dans .elding.json`));
48
72
  console.log(chalk.dim("Ajoutez .elding.json à votre .gitignore si besoin."));
49
73
  }
@@ -0,0 +1 @@
1
+ export declare function keys(): Promise<void>;
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.keys = keys;
4
+ const api_js_1 = require("../lib/api.js");
5
+ const config_js_1 = require("../lib/config.js");
6
+ const session_js_1 = require("../lib/session.js");
7
+ const terminal_js_1 = require("../lib/terminal.js");
8
+ async function keys() {
9
+ const { default: chalk } = await import("chalk");
10
+ const { default: ora } = await import("ora");
11
+ const project = (0, config_js_1.readProject)();
12
+ if (!project) {
13
+ console.error(chalk.red("Projet non initialisé. Lancez `elding init` ou `elding use <set>`."));
14
+ process.exit(1);
15
+ }
16
+ const spinner = ora("Récupération des clés...").start();
17
+ const accessToken = await (0, session_js_1.requireAccessToken)();
18
+ const list = await (0, api_js_1.listKeys)(accessToken, project.setId);
19
+ spinner.stop();
20
+ console.log(chalk.dim(`Set : ${(0, terminal_js_1.safeText)(project.setName)}`));
21
+ if (list.length === 0) {
22
+ console.log(chalk.yellow("Aucune clé dans ce set."));
23
+ return;
24
+ }
25
+ for (const k of list) {
26
+ const host = k.allowedHost
27
+ ? chalk.dim(` → ${(0, terminal_js_1.safeText)(k.allowedHost)}`)
28
+ : chalk.yellow(" → aucun domaine (non verrouillé)");
29
+ console.log(` ${(0, terminal_js_1.safeText)(k.name)}${host}`);
30
+ }
31
+ }
@@ -7,52 +7,67 @@ exports.login = login;
7
7
  const http_1 = __importDefault(require("http"));
8
8
  const crypto_1 = __importDefault(require("crypto"));
9
9
  const config_js_1 = require("../lib/config.js");
10
- const BASE_URL = process.env.ELDING_API_URL ?? "https://app.elding.io";
10
+ const api_js_1 = require("../lib/api.js");
11
+ const terminal_js_1 = require("../lib/terminal.js");
11
12
  const TIMEOUT_MS = 5 * 60 * 1000;
12
- function randomPort() {
13
- return Math.floor(Math.random() * (65535 - 49152 + 1)) + 49152;
14
- }
15
13
  async function login() {
16
14
  const { default: chalk } = await import("chalk");
17
15
  const { default: open } = await import("open");
18
16
  const { default: ora } = await import("ora");
19
17
  const state = crypto_1.default.randomBytes(16).toString("hex");
20
- const port = randomPort();
21
- const callbackUrl = `http://localhost:${port}`;
22
- const authUrl = `${BASE_URL}/cli` +
23
- `?state=${encodeURIComponent(state)}` +
24
- `&callback=${encodeURIComponent(callbackUrl)}`;
25
18
  const spinner = ora("En attente d'autorisation dans le navigateur...").start();
26
19
  const token = await new Promise((resolve, reject) => {
27
20
  const timeout = setTimeout(() => {
28
21
  server.close();
29
22
  reject(new Error("Timeout — aucune réponse après 5 minutes"));
30
23
  }, TIMEOUT_MS);
31
- const server = http_1.default.createServer((req, res) => {
32
- const url = new URL(req.url ?? "/", `http://localhost:${port}`);
33
- const receivedToken = url.searchParams.get("token");
24
+ const server = http_1.default.createServer(async (req, res) => {
25
+ const addr = server.address();
26
+ const port = typeof addr === "object" && addr ? addr.port : 0;
27
+ const callbackUrl = `http://127.0.0.1:${port}`;
28
+ const url = new URL(req.url ?? "/", callbackUrl);
29
+ const receivedCode = url.searchParams.get("code");
34
30
  const receivedState = url.searchParams.get("state");
35
- const tokenValid = typeof receivedToken === "string" &&
36
- receivedToken.startsWith("eld_rt_") &&
37
- receivedToken.length === 7 + 64; // "eld_rt_" + 32 bytes hex
38
- if (receivedState !== state || !tokenValid) {
31
+ const codeValid = typeof receivedCode === "string" &&
32
+ /^[A-Za-z0-9._~-]{16,512}$/.test(receivedCode);
33
+ if (receivedState !== state || !codeValid) {
39
34
  res.writeHead(400, { "Content-Type": "text/html; charset=utf-8" });
40
35
  res.end("<p>Paramètres invalides. Fermez cet onglet.</p>");
41
36
  return;
42
37
  }
43
- res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
44
- res.end(`<!DOCTYPE html><html><head><meta charset="utf-8"></head><body style="font-family:sans-serif;padding:2rem">
45
- <p>✅ <strong>Authentification réussie.</strong> Vous pouvez fermer cet onglet.</p>
46
- </body></html>`);
47
- clearTimeout(timeout);
48
- server.close();
49
- resolve(receivedToken);
38
+ try {
39
+ const refreshToken = await (0, api_js_1.exchangeLoginCode)(receivedCode, state, callbackUrl);
40
+ res.writeHead(200, {
41
+ "Content-Type": "text/html; charset=utf-8",
42
+ "Referrer-Policy": "no-referrer",
43
+ "Cache-Control": "no-store",
44
+ });
45
+ res.end(`<!DOCTYPE html><html><head><meta charset="utf-8"><script>history.replaceState(null,"","/")</script></head><body style="font-family:sans-serif;padding:2rem">
46
+ <p><strong>Authentification réussie.</strong> Vous pouvez fermer cet onglet.</p>
47
+ </body></html>`);
48
+ clearTimeout(timeout);
49
+ server.close();
50
+ resolve(refreshToken);
51
+ }
52
+ catch (err) {
53
+ res.writeHead(502, { "Content-Type": "text/html; charset=utf-8" });
54
+ res.end("<p>Impossible de finaliser l'authentification. Fermez cet onglet et relancez le login.</p>");
55
+ clearTimeout(timeout);
56
+ server.close();
57
+ reject(new Error((0, terminal_js_1.safeError)(err)));
58
+ }
50
59
  });
51
60
  server.on("error", (err) => {
52
61
  clearTimeout(timeout);
53
62
  reject(err);
54
63
  });
55
- server.listen(port, "127.0.0.1", () => {
64
+ server.listen(0, "127.0.0.1", () => {
65
+ const addr = server.address();
66
+ const port = typeof addr === "object" && addr ? addr.port : 0;
67
+ const callbackUrl = `http://127.0.0.1:${port}`;
68
+ const authUrl = `${api_js_1.BASE_URL}/cli` +
69
+ `?state=${encodeURIComponent(state)}` +
70
+ `&callback=${encodeURIComponent(callbackUrl)}`;
56
71
  open(authUrl).catch((err) => {
57
72
  spinner.warn(`Impossible d'ouvrir le navigateur automatiquement.`);
58
73
  console.log(chalk.cyan(`Ouvrez manuellement : ${authUrl}`));
@@ -61,5 +76,5 @@ async function login() {
61
76
  });
62
77
  (0, config_js_1.writeConfig)({ refreshToken: token });
63
78
  spinner.succeed(chalk.green("Connecté avec succès."));
64
- console.log(chalk.dim("Token sauvegardé dans ~/.elding/config.json"));
79
+ console.log(chalk.dim("Token sauvegardé dans le trousseau de votre OS."));
65
80
  }
@@ -0,0 +1 @@
1
+ export declare function open(): Promise<void>;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.open = open;
4
+ const api_js_1 = require("../lib/api.js");
5
+ async function open() {
6
+ const { default: chalk } = await import("chalk");
7
+ const { default: openUrl } = await import("open");
8
+ const url = `${api_js_1.BASE_URL}/vault`;
9
+ await openUrl(url).catch(() => {
10
+ console.log(chalk.cyan(`Ouvrez manuellement : ${url}`));
11
+ });
12
+ console.log(chalk.dim(`Vault ouvert : ${url}`));
13
+ }
@@ -1 +1,6 @@
1
- export declare function proxy(cmd: string, args: string[]): Promise<void>;
1
+ export type ProxyOptions = {
2
+ verbose?: boolean;
3
+ reportLogs?: boolean;
4
+ shell?: boolean;
5
+ };
6
+ export declare function proxy(cmd: string, args: string[], options?: ProxyOptions): Promise<void>;
@@ -5,7 +5,10 @@ const child_process_1 = require("child_process");
5
5
  const config_js_1 = require("../lib/config.js");
6
6
  const api_js_1 = require("../lib/api.js");
7
7
  const proxyServer_js_1 = require("../lib/proxyServer.js");
8
- async function proxy(cmd, args) {
8
+ const logBatcher_js_1 = require("../lib/logBatcher.js");
9
+ const trust_js_1 = require("../lib/trust.js");
10
+ const terminal_js_1 = require("../lib/terminal.js");
11
+ async function proxy(cmd, args, options = {}) {
9
12
  const { default: chalk } = await import("chalk");
10
13
  const { default: ora } = await import("ora");
11
14
  const config = (0, config_js_1.readConfig)();
@@ -18,6 +21,10 @@ async function proxy(cmd, args) {
18
21
  console.error(chalk.red("Projet non initialisé. Lancez `elding init` d'abord."));
19
22
  process.exit(1);
20
23
  }
24
+ await (0, trust_js_1.ensureProjectTrusted)(project);
25
+ if (!options.shell && /\s/.test(cmd)) {
26
+ throw new Error("Commande invalide sans --shell. Passez le binaire et ses arguments separement, ou ajoutez --shell explicitement.");
27
+ }
21
28
  const spinner = ora("Démarrage du proxy...").start();
22
29
  let secrets;
23
30
  let hosts;
@@ -26,12 +33,17 @@ async function proxy(cmd, args) {
26
33
  ({ secrets, hosts } = await (0, api_js_1.fetchSecrets)(accessToken, project.setId));
27
34
  }
28
35
  catch (err) {
29
- spinner.fail(chalk.red(err instanceof Error ? err.message : "Erreur inconnue"));
36
+ spinner.fail(chalk.red((0, terminal_js_1.safeError)(err)));
30
37
  process.exit(1);
31
38
  }
32
- const server = await (0, proxyServer_js_1.startProxy)(secrets, hosts);
33
- spinner.succeed(chalk.green(`Proxy actif sur ${server.url} — ${Object.keys(secrets).length} secret(s)`));
39
+ const batcher = options.reportLogs
40
+ ? (0, logBatcher_js_1.createLogBatcher)(config.refreshToken, project.setId, project.setName)
41
+ : null;
42
+ const server = await (0, proxyServer_js_1.startProxy)(secrets, hosts, !!options.verbose, batcher ? (e) => batcher.add(e) : undefined);
43
+ spinner.succeed(chalk.green(`Proxy actif sur ${server.url} — ${Object.keys(secrets).length} secret(s) pour ${(0, terminal_js_1.safeText)(project.setName)}`));
34
44
  console.log(chalk.dim("Les clés restent dans le proxy, jamais dans la mémoire de l'app."));
45
+ if (!options.reportLogs)
46
+ console.log(chalk.dim("Logs cloud proxy désactivés. Ajoutez --report-logs pour les envoyer."));
35
47
  const child = (0, child_process_1.spawn)(cmd, args, {
36
48
  env: {
37
49
  ...process.env,
@@ -39,13 +51,17 @@ async function proxy(cmd, args) {
39
51
  ELDING_PROXY_TOKEN: server.token,
40
52
  },
41
53
  stdio: "inherit",
42
- shell: true,
54
+ shell: !!options.shell,
43
55
  });
44
- const shutdown = () => server.close();
56
+ const shutdown = async () => {
57
+ server.close();
58
+ await batcher?.stop();
59
+ };
45
60
  process.on("SIGINT", shutdown);
46
61
  process.on("SIGTERM", shutdown);
47
- child.on("exit", (code) => {
62
+ child.on("exit", async (code) => {
48
63
  server.close();
64
+ await batcher?.stop(); // flush les derniers logs
49
65
  process.exit(code ?? 0);
50
66
  });
51
67
  }
@@ -1 +1,4 @@
1
- export declare function run(cmd: string, args: string[]): Promise<void>;
1
+ export type RunOptions = {
2
+ shell?: boolean;
3
+ };
4
+ export declare function run(cmd: string, args: string[], options?: RunOptions): Promise<void>;
@@ -4,7 +4,10 @@ exports.run = run;
4
4
  const child_process_1 = require("child_process");
5
5
  const config_js_1 = require("../lib/config.js");
6
6
  const api_js_1 = require("../lib/api.js");
7
- async function run(cmd, args) {
7
+ const env_js_1 = require("../lib/env.js");
8
+ const trust_js_1 = require("../lib/trust.js");
9
+ const terminal_js_1 = require("../lib/terminal.js");
10
+ async function run(cmd, args, options = {}) {
8
11
  const { default: chalk } = await import("chalk");
9
12
  const { default: ora } = await import("ora");
10
13
  const config = (0, config_js_1.readConfig)();
@@ -17,22 +20,30 @@ async function run(cmd, args) {
17
20
  console.error(chalk.red("Projet non initialisé. Lancez `elding init` d'abord."));
18
21
  process.exit(1);
19
22
  }
23
+ await (0, trust_js_1.ensureProjectTrusted)(project);
24
+ if (!options.shell && /\s/.test(cmd)) {
25
+ throw new Error("Commande invalide sans --shell. Passez le binaire et ses arguments separement, ou ajoutez --shell explicitement.");
26
+ }
20
27
  const spinner = ora("Récupération des secrets...").start();
21
28
  let secrets;
22
29
  try {
23
30
  const accessToken = await (0, api_js_1.exchangeToken)(config.refreshToken);
24
- ({ secrets } = await (0, api_js_1.fetchSecrets)(accessToken, project.setId));
25
- spinner.succeed(chalk.green(`${Object.keys(secrets).length} secret(s) chargé(s).`));
31
+ ({ secrets } = await (0, api_js_1.fetchSecrets)(accessToken, project.setId, "run"));
32
+ spinner.succeed(chalk.green(`${Object.keys(secrets).length} secret(s) chargé(s) pour ${(0, terminal_js_1.safeText)(project.setName)}.`));
26
33
  }
27
34
  catch (err) {
28
- spinner.fail(chalk.red(err instanceof Error ? err.message : "Erreur inconnue"));
35
+ spinner.fail(chalk.red((0, terminal_js_1.safeError)(err)));
29
36
  process.exit(1);
30
37
  }
31
- const env = { ...process.env, ...secrets };
38
+ const { env: safeSecrets, rejected } = (0, env_js_1.filterSecretsForEnv)(secrets);
39
+ if (rejected.length > 0) {
40
+ throw new Error(`Secrets refuses car leurs noms sont dangereux pour l'environnement: ${rejected.map((name) => (0, terminal_js_1.safeText)(name, 80)).join(", ")}`);
41
+ }
42
+ const env = { ...process.env, ...safeSecrets };
32
43
  const result = (0, child_process_1.spawnSync)(cmd, args, {
33
44
  env,
34
45
  stdio: "inherit",
35
- shell: true,
46
+ shell: !!options.shell,
36
47
  });
37
48
  if (result.error) {
38
49
  console.error(chalk.red(`Impossible de lancer la commande : ${result.error.message}`));
@@ -0,0 +1 @@
1
+ export declare function sets(): Promise<void>;
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sets = sets;
4
+ const api_js_1 = require("../lib/api.js");
5
+ const config_js_1 = require("../lib/config.js");
6
+ const session_js_1 = require("../lib/session.js");
7
+ const terminal_js_1 = require("../lib/terminal.js");
8
+ async function sets() {
9
+ const { default: chalk } = await import("chalk");
10
+ const { default: ora } = await import("ora");
11
+ const spinner = ora("Récupération des sets...").start();
12
+ const accessToken = await (0, session_js_1.requireAccessToken)();
13
+ const list = await (0, api_js_1.listSets)(accessToken);
14
+ spinner.stop();
15
+ if (list.length === 0) {
16
+ console.log(chalk.yellow("Aucun set. Créez-en un sur le vault."));
17
+ return;
18
+ }
19
+ const activeId = (0, config_js_1.readProject)()?.setId;
20
+ for (const s of list) {
21
+ const marker = s.id === activeId ? chalk.green("●") : chalk.dim("○");
22
+ const cleanName = (0, terminal_js_1.safeText)(s.name);
23
+ const name = s.id === activeId ? chalk.green(cleanName) : cleanName;
24
+ console.log(`${marker} ${name} ${chalk.dim(`(${(0, terminal_js_1.safeText)(s.workspaceName)})`)}`);
25
+ }
26
+ }
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.status = status;
4
4
  const config_js_1 = require("../lib/config.js");
5
5
  const api_js_1 = require("../lib/api.js");
6
+ const terminal_js_1 = require("../lib/terminal.js");
6
7
  async function status() {
7
8
  const { default: chalk } = await import("chalk");
8
9
  const config = (0, config_js_1.readConfig)();
@@ -23,7 +24,7 @@ async function status() {
23
24
  const project = (0, config_js_1.readProject)();
24
25
  const proxyActive = !!process.env.ELDING_PROXY_URL;
25
26
  console.log(chalk.green("● Connecté"));
26
- console.log(` ${chalk.dim("Utilisateur")} ${user.email}${user.name ? chalk.dim(` (${user.name})`) : ""}`);
27
- console.log(` ${chalk.dim("Set actif")} ${project ? `${project.setName} ${chalk.dim(`(${project.setId})`)}` : chalk.yellow("aucun — `elding init`")}`);
27
+ console.log(` ${chalk.dim("Utilisateur")} ${(0, terminal_js_1.safeText)(user.email)}${user.name ? chalk.dim(` (${(0, terminal_js_1.safeText)(user.name)})`) : ""}`);
28
+ console.log(` ${chalk.dim("Set actif")} ${project ? `${(0, terminal_js_1.safeText)(project.setName)} ${chalk.dim(`(${(0, terminal_js_1.safeText)(project.setId)})`)}` : chalk.yellow("aucun — `elding init`")}`);
28
29
  console.log(` ${chalk.dim("Proxy")} ${proxyActive ? chalk.green("actif") : chalk.dim("inactif")}`);
29
30
  }
@@ -0,0 +1 @@
1
+ export declare function use(nameArg: string): Promise<void>;
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.use = use;
4
+ const api_js_1 = require("../lib/api.js");
5
+ const config_js_1 = require("../lib/config.js");
6
+ const session_js_1 = require("../lib/session.js");
7
+ const terminal_js_1 = require("../lib/terminal.js");
8
+ async function use(nameArg) {
9
+ const { default: chalk } = await import("chalk");
10
+ const { default: ora } = await import("ora");
11
+ const spinner = ora("Récupération des sets...").start();
12
+ const accessToken = await (0, session_js_1.requireAccessToken)();
13
+ const list = await (0, api_js_1.listSets)(accessToken);
14
+ spinner.stop();
15
+ const query = nameArg.trim().toLowerCase();
16
+ const matches = list.filter((s) => s.name.toLowerCase() === query);
17
+ const candidates = matches.length ? matches : list.filter((s) => s.name.toLowerCase().includes(query));
18
+ if (candidates.length === 0) {
19
+ console.error(chalk.red(`Aucun set nommé "${(0, terminal_js_1.safeText)(nameArg)}".`) + chalk.dim(" Voir `elding sets`."));
20
+ process.exit(1);
21
+ }
22
+ if (candidates.length > 1) {
23
+ console.error(chalk.red(`Plusieurs sets correspondent à "${(0, terminal_js_1.safeText)(nameArg)}" :`));
24
+ candidates.forEach((s) => console.error(chalk.dim(` - ${(0, terminal_js_1.safeText)(s.name)}`)));
25
+ process.exit(1);
26
+ }
27
+ const set = candidates[0];
28
+ const project = {
29
+ setId: set.id,
30
+ setName: set.name,
31
+ workspaceId: set.workspaceId,
32
+ workspaceName: set.workspaceName,
33
+ };
34
+ (0, config_js_1.writeProject)(project);
35
+ (0, config_js_1.trustProject)(project);
36
+ console.log(chalk.green(`✓ Set actif : "${(0, terminal_js_1.safeText)(set.name)}"`));
37
+ }
@@ -0,0 +1 @@
1
+ export declare function whoami(): Promise<void>;
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.whoami = whoami;
4
+ const api_js_1 = require("../lib/api.js");
5
+ const session_js_1 = require("../lib/session.js");
6
+ const terminal_js_1 = require("../lib/terminal.js");
7
+ async function whoami() {
8
+ const { default: chalk } = await import("chalk");
9
+ const accessToken = await (0, session_js_1.requireAccessToken)();
10
+ const me = await (0, api_js_1.getMe)(accessToken);
11
+ console.log(`${(0, terminal_js_1.safeText)(me.email)}${me.name ? chalk.dim(` (${(0, terminal_js_1.safeText)(me.name)})`) : ""}`);
12
+ }
package/dist/index.js CHANGED
@@ -8,11 +8,17 @@ const run_js_1 = require("./commands/run.js");
8
8
  const proxy_js_1 = require("./commands/proxy.js");
9
9
  const logout_js_1 = require("./commands/logout.js");
10
10
  const status_js_1 = require("./commands/status.js");
11
+ const sets_js_1 = require("./commands/sets.js");
12
+ const use_js_1 = require("./commands/use.js");
13
+ const keys_js_1 = require("./commands/keys.js");
14
+ const doctor_js_1 = require("./commands/doctor.js");
15
+ const open_js_1 = require("./commands/open.js");
16
+ const whoami_js_1 = require("./commands/whoami.js");
11
17
  const program = new commander_1.Command();
12
18
  program
13
19
  .name("elding")
14
20
  .description("Elding CLI — secrets depuis le vault, zéro .env")
15
- .version("0.1.0");
21
+ .version("0.3.0");
16
22
  program
17
23
  .command("login")
18
24
  .description("Authentifier le CLI via le navigateur")
@@ -32,23 +38,29 @@ program
32
38
  });
33
39
  });
34
40
  program
35
- .command("run <cmd>")
41
+ .command("run <cmd> [args...]")
36
42
  .description("Lancer une commande avec les secrets injectés en variables d'environnement")
43
+ .option("--shell", "Executer via le shell systeme (a utiliser seulement si necessaire)")
37
44
  .allowUnknownOption()
38
- .action(async (cmd, options, command) => {
39
- const args = command.args.slice(1);
40
- await (0, run_js_1.run)(cmd, args).catch((err) => {
45
+ .action(async (cmd, args = [], options) => {
46
+ await (0, run_js_1.run)(cmd, args, { shell: !!options.shell }).catch((err) => {
41
47
  console.error(err.message);
42
48
  process.exit(1);
43
49
  });
44
50
  });
45
51
  program
46
- .command("proxy <cmd>")
52
+ .command("proxy <cmd> [args...]")
47
53
  .description("Lancer une commande derrière un proxy local qui injecte les clés — jamais en mémoire de l'app")
54
+ .option("-v, --verbose", "Logger chaque requête (méthode/host/status/latence)")
55
+ .option("--report-logs", "Envoyer les metadonnees de requetes proxy au vault")
56
+ .option("--shell", "Executer via le shell systeme (a utiliser seulement si necessaire)")
48
57
  .allowUnknownOption()
49
- .action(async (cmd, options, command) => {
50
- const args = command.args.slice(1);
51
- await (0, proxy_js_1.proxy)(cmd, args).catch((err) => {
58
+ .action(async (cmd, args = [], options) => {
59
+ await (0, proxy_js_1.proxy)(cmd, args, {
60
+ verbose: !!options.verbose,
61
+ reportLogs: !!options.reportLogs,
62
+ shell: !!options.shell,
63
+ }).catch((err) => {
52
64
  console.error(err.message);
53
65
  process.exit(1);
54
66
  });
@@ -71,4 +83,58 @@ program
71
83
  process.exit(1);
72
84
  });
73
85
  });
86
+ program
87
+ .command("sets")
88
+ .description("Lister les sets accessibles")
89
+ .action(async () => {
90
+ await (0, sets_js_1.sets)().catch((err) => {
91
+ console.error(err.message);
92
+ process.exit(1);
93
+ });
94
+ });
95
+ program
96
+ .command("use <name>")
97
+ .description("Changer le set actif du projet")
98
+ .action(async (name) => {
99
+ await (0, use_js_1.use)(name).catch((err) => {
100
+ console.error(err.message);
101
+ process.exit(1);
102
+ });
103
+ });
104
+ program
105
+ .command("keys")
106
+ .description("Lister les noms de clés du set actif (jamais les valeurs)")
107
+ .action(async () => {
108
+ await (0, keys_js_1.keys)().catch((err) => {
109
+ console.error(err.message);
110
+ process.exit(1);
111
+ });
112
+ });
113
+ program
114
+ .command("doctor")
115
+ .description("Diagnostiquer la configuration (connexion, set, clés, proxy)")
116
+ .action(async () => {
117
+ await (0, doctor_js_1.doctor)().catch((err) => {
118
+ console.error(err.message);
119
+ process.exit(1);
120
+ });
121
+ });
122
+ program
123
+ .command("open")
124
+ .description("Ouvrir le vault dans le navigateur")
125
+ .action(async () => {
126
+ await (0, open_js_1.open)().catch((err) => {
127
+ console.error(err.message);
128
+ process.exit(1);
129
+ });
130
+ });
131
+ program
132
+ .command("whoami")
133
+ .description("Afficher l'utilisateur connecté")
134
+ .action(async () => {
135
+ await (0, whoami_js_1.whoami)().catch((err) => {
136
+ console.error(err.message);
137
+ process.exit(1);
138
+ });
139
+ });
74
140
  program.parse();
package/dist/lib/api.d.ts CHANGED
@@ -1,8 +1,18 @@
1
+ export declare const BASE_URL: string;
1
2
  export type ApiKeySetItem = {
2
3
  id: string;
3
4
  name: string;
5
+ workspaceId: string;
6
+ workspaceName: string;
4
7
  };
8
+ export type KeyItem = {
9
+ name: string;
10
+ allowedHost: string | null;
11
+ };
12
+ export declare function listKeys(accessToken: string, setId: string): Promise<KeyItem[]>;
5
13
  export declare function exchangeToken(refreshToken: string): Promise<string>;
14
+ export declare function exchangeLoginCode(code: string, state: string, callbackUrl: string): Promise<string>;
15
+ export declare function reportProxyLogs(accessToken: string, setId: string, setName: string, entries: unknown[]): Promise<void>;
6
16
  export declare function revokeToken(refreshToken: string): Promise<void>;
7
17
  export declare function getMe(accessToken: string): Promise<{
8
18
  email: string;
@@ -13,4 +23,4 @@ export type SecretsResult = {
13
23
  secrets: Record<string, string>;
14
24
  hosts: Record<string, string>;
15
25
  };
16
- export declare function fetchSecrets(accessToken: string, setId: string): Promise<SecretsResult>;
26
+ export declare function fetchSecrets(accessToken: string, setId: string, mode?: "run" | "proxy"): Promise<SecretsResult>;