@pqc-sdk/cli 0.1.1 → 0.2.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.
package/README.md CHANGED
@@ -3,23 +3,26 @@
3
3
  [![CI](https://github.com/jeloercc/pqc-sdk/actions/workflows/ci.yml/badge.svg)](https://github.com/jeloercc/pqc-sdk/actions/workflows/ci.yml)
4
4
  [![npm](https://img.shields.io/npm/v/%40pqc-sdk%2Fcli)](https://www.npmjs.com/package/@pqc-sdk/cli)
5
5
 
6
- CLI de [@pqc-sdk/core](https://www.npmjs.com/package/@pqc-sdk/core): proyectos
7
- post-cuánticos en un comando.
6
+ CLI for [@pqc-sdk/core](https://www.npmjs.com/package/@pqc-sdk/core):
7
+ post-quantum projects in one command.
8
8
 
9
9
  ```bash
10
- # Inicializar proyecto: config + keys de desarrollo + ejemplo funcional
10
+ # Initialize a project: config + development keys + working example
11
11
  npx @pqc-sdk/cli init
12
12
 
13
- # Generar keys serializadas en base64url
13
+ # Generate keys serialized as base64url
14
14
  npx @pqc-sdk/cli keygen --algorithm ml-dsa-65 --out keys/
15
15
 
16
- # Detectar crypto pre-cuántico (RSA/ECDSA/ECDH) y qué migrar a PQC
16
+ # Heuristically detect pre-quantum crypto (RSA/ECDSA/ECDH) and what to migrate to PQC
17
17
  npx @pqc-sdk/cli audit
18
18
  ```
19
19
 
20
- `audit` sale con código 1 si encuentra crypto a migrar usable como gate de CI.
21
- El output usa colores solo cuando hay TTY: legible en logs y pipes.
20
+ `audit` is a best-effort regex scan of your dependencies and source: expect the
21
+ occasional false positive or false negative, and treat it as a starting point,
22
+ not a proof. Files larger than 1 MiB are skipped and reported. It exits with
23
+ code 1 when it finds crypto to migrate — usable as a CI gate. Output uses colors
24
+ only when there is a TTY: readable in logs and pipes.
22
25
 
23
- ## Licencia
26
+ ## License
24
27
 
25
28
  [MIT](./LICENSE)
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@
4
4
  import { defineCommand as defineCommand4, runMain } from "citty";
5
5
 
6
6
  // src/commands/audit.ts
7
- import { readFile, readdir } from "fs/promises";
7
+ import { readFile, readdir, stat } from "fs/promises";
8
8
  import { existsSync } from "fs";
9
9
  import { join, relative } from "path";
10
10
  import { defineCommand } from "citty";
@@ -23,54 +23,58 @@ var item = (message) => {
23
23
  };
24
24
  var finding = (location, what, migrateTo) => {
25
25
  console.log(` ${pc.red("\u25CF")} ${pc.bold(location)} \u2014 ${what}`);
26
- console.log(` ${pc.dim("migrar a:")} ${pc.cyan(migrateTo)}`);
26
+ console.log(` ${pc.dim("migrate to:")} ${pc.cyan(migrateTo)}`);
27
27
  };
28
28
  var heading = (message) => {
29
29
  console.log(pc.bold(message));
30
30
  };
31
+ var note = (message) => {
32
+ console.log(pc.dim(message));
33
+ };
31
34
 
32
35
  // src/commands/audit.ts
36
+ var MAX_FILE_BYTES = 1024 * 1024;
33
37
  var ML_DSA = "ML-DSA-65 (pqc.sign / pqc.verify)";
34
38
  var ML_KEM = "ML-KEM-768 + AES-256-GCM (pqc.encrypt / pqc.decrypt)";
35
39
  var RISKY_PACKAGES = {
36
- jsonwebtoken: { what: "JWTs firmados con RSA/ECDSA (RS256/ES256)", migrateTo: ML_DSA },
37
- jose: { what: "JOSE/JWT con algoritmos RSA/ECDSA", migrateTo: ML_DSA },
38
- elliptic: { what: "Curvas el\xEDpticas cl\xE1sicas (ECDSA/ECDH)", migrateTo: `${ML_DSA} y ${ML_KEM}` },
39
- secp256k1: { what: "Firmas ECDSA sobre secp256k1", migrateTo: ML_DSA },
40
- "node-rsa": { what: "Cifrado y firmas RSA", migrateTo: `${ML_KEM} y ${ML_DSA}` },
41
- "node-forge": { what: "RSA/X.509 cl\xE1sico", migrateTo: `${ML_KEM} y ${ML_DSA}` },
42
- tweetnacl: { what: "Ed25519/X25519 (pre-cu\xE1ntico)", migrateTo: `${ML_DSA} y ${ML_KEM}` }
40
+ jsonwebtoken: { what: "JWTs signed with RSA/ECDSA (RS256/ES256)", migrateTo: ML_DSA },
41
+ jose: { what: "JOSE/JWT with RSA/ECDSA algorithms", migrateTo: ML_DSA },
42
+ elliptic: { what: "Classic elliptic curves (ECDSA/ECDH)", migrateTo: `${ML_DSA} and ${ML_KEM}` },
43
+ secp256k1: { what: "ECDSA signatures over secp256k1", migrateTo: ML_DSA },
44
+ "node-rsa": { what: "RSA encryption and signatures", migrateTo: `${ML_KEM} and ${ML_DSA}` },
45
+ "node-forge": { what: "Classic RSA/X.509", migrateTo: `${ML_KEM} and ${ML_DSA}` },
46
+ tweetnacl: { what: "Ed25519/X25519 (pre-quantum)", migrateTo: `${ML_DSA} and ${ML_KEM}` }
43
47
  };
44
48
  var CODE_PATTERNS = [
45
49
  {
46
50
  re: /create(?:Sign|Verify)\s*\(/,
47
- what: "firma RSA/ECDSA v\xEDa node:crypto (createSign/createVerify)",
51
+ what: "RSA/ECDSA signing via node:crypto (createSign/createVerify)",
48
52
  migrateTo: ML_DSA
49
53
  },
50
54
  {
51
55
  re: /createECDH\s*\(|\.diffieHellman\s*\(/,
52
- what: "intercambio de claves ECDH/DH",
56
+ what: "ECDH/DH key exchange",
53
57
  migrateTo: ML_KEM
54
58
  },
55
59
  {
56
60
  re: /publicEncrypt\s*\(|privateDecrypt\s*\(/,
57
- what: "cifrado RSA (publicEncrypt/privateDecrypt)",
61
+ what: "RSA encryption (publicEncrypt/privateDecrypt)",
58
62
  migrateTo: ML_KEM
59
63
  },
60
64
  {
61
65
  re: /generateKeyPair(?:Sync)?\s*\(\s*['"](?:rsa|rsa-pss|dsa|ec|ed25519|ed448|x25519|x448)['"]/,
62
- what: "generaci\xF3n de keypair pre-cu\xE1ntico",
63
- migrateTo: "pqc.keys.generate (ML-KEM-768 para cifrado, ML-DSA-65 para firmas)"
66
+ what: "pre-quantum keypair generation",
67
+ migrateTo: "pqc.keys.generate (ML-KEM-768 for encryption, ML-DSA-65 for signatures)"
64
68
  },
65
69
  {
66
70
  re: /['"`](?:RS|ES|PS)(?:256|384|512)['"`]/,
67
- what: "JWT con algoritmo de firma RSA/ECDSA",
71
+ what: "JWT with an RSA/ECDSA signing algorithm",
68
72
  migrateTo: ML_DSA
69
73
  },
70
74
  {
71
75
  re: /['"`](?:RSA-OAEP|ECDH|ECDSA)['"`]/,
72
- what: "WebCrypto con algoritmo pre-cu\xE1ntico",
73
- migrateTo: `${ML_KEM} o ${ML_DSA}`
76
+ what: "WebCrypto with a pre-quantum algorithm",
77
+ migrateTo: `${ML_KEM} or ${ML_DSA}`
74
78
  }
75
79
  ];
76
80
  var SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([".js", ".mjs", ".cjs", ".ts", ".mts", ".cts", ".jsx", ".tsx"]);
@@ -106,7 +110,12 @@ async function auditPackageJson(cwd) {
106
110
  }
107
111
  async function auditSources(cwd) {
108
112
  const findings = [];
113
+ const skipped = [];
109
114
  for (const file of await collectSourceFiles(cwd)) {
115
+ if ((await stat(file)).size > MAX_FILE_BYTES) {
116
+ skipped.push(relative(cwd, file));
117
+ continue;
118
+ }
110
119
  const lines = (await readFile(file, "utf8")).split("\n");
111
120
  lines.forEach((line, index) => {
112
121
  for (const { re, what, migrateTo } of CODE_PATTERNS) {
@@ -116,28 +125,37 @@ async function auditSources(cwd) {
116
125
  }
117
126
  });
118
127
  }
119
- return findings;
128
+ return { findings, skipped };
120
129
  }
121
130
  var audit = defineCommand({
122
131
  meta: {
123
132
  name: "audit",
124
- description: "Detecta crypto pre-cu\xE1ntico y sugiere el equivalente PQC"
133
+ description: "Heuristically detect pre-quantum crypto (best-effort regex scan) and suggest the PQC equivalent"
125
134
  },
126
135
  async run() {
127
136
  const cwd = process.cwd();
128
- const findings = [...await auditPackageJson(cwd), ...await auditSources(cwd)];
137
+ const { findings: sourceFindings, skipped } = await auditSources(cwd);
138
+ const findings = [...await auditPackageJson(cwd), ...sourceFindings];
139
+ note(
140
+ "Heuristic, best-effort regex scan \u2014 expect occasional false positives and false negatives."
141
+ );
142
+ if (skipped.length > 0) {
143
+ note(
144
+ `Skipped ${skipped.length} file(s) larger than ${MAX_FILE_BYTES / 1024 / 1024} MiB: ${skipped.join(", ")}`
145
+ );
146
+ }
129
147
  if (findings.length === 0) {
130
- ok("Sin crypto pre-cu\xE1ntico detectado.");
148
+ ok("No pre-quantum crypto detected.");
131
149
  return;
132
150
  }
133
- heading(`Crypto pre-cu\xE1ntico detectado (${findings.length} hallazgos):`);
151
+ heading(`Pre-quantum crypto detected (${findings.length} findings):`);
134
152
  for (const f of findings) {
135
153
  finding(f.location, f.what, f.migrateTo);
136
154
  }
137
155
  console.log();
138
156
  console.log(
139
157
  pc2.yellow(
140
- `${findings.length} usos a migrar. Gu\xEDa de algoritmos: FIPS 203 (ML-KEM) cifrado, FIPS 204 (ML-DSA) firmas.`
158
+ `${findings.length} usages to migrate. Algorithm guide: FIPS 203 (ML-KEM) encryption, FIPS 204 (ML-DSA) signatures.`
141
159
  )
142
160
  );
143
161
  process.exitCode = 1;
@@ -157,18 +175,30 @@ import { SUPPORTED_ALGORITHMS, pqc } from "@pqc-sdk/core";
157
175
  function assertSupportedAlgorithm(value) {
158
176
  if (!SUPPORTED_ALGORITHMS.includes(value)) {
159
177
  throw new Error(
160
- `Algoritmo no soportado: ${value} (soportados: ${SUPPORTED_ALGORITHMS.join(", ")})`
178
+ `Unsupported algorithm: ${value} (supported: ${SUPPORTED_ALGORITHMS.join(", ")})`
161
179
  );
162
180
  }
163
181
  return value;
164
182
  }
183
+ function assertSafeName(value) {
184
+ if (value === "") {
185
+ throw new Error("Invalid --name: must not be empty.");
186
+ }
187
+ if (value.includes("/") || value.includes("\\")) {
188
+ throw new Error('Invalid --name: must not contain path separators ("/" or "\\").');
189
+ }
190
+ if (value.includes("..")) {
191
+ throw new Error('Invalid --name: must not contain "..".');
192
+ }
193
+ return value;
194
+ }
165
195
  async function writeKeyPair(directory, baseName, algorithm, force) {
166
196
  const publicPath = join2(directory, `${baseName}.public.pqc`);
167
197
  const secretPath = join2(directory, `${baseName}.secret.pqc`);
168
198
  if (!force) {
169
199
  for (const path of [publicPath, secretPath]) {
170
200
  if (existsSync2(path)) {
171
- throw new Error(`${path} ya existe. Us\xE1 --force para sobreescribirla.`);
201
+ throw new Error(`${path} already exists. Use --force to overwrite it.`);
172
202
  }
173
203
  }
174
204
  }
@@ -190,22 +220,22 @@ var CONFIG = {
190
220
  };
191
221
  var EXAMPLE = `import { pqc } from '@pqc-sdk/core';
192
222
 
193
- // Roundtrip completo: generar keys, cifrar y descifrar.
194
- const pair = await pqc.keys.generate(); // ML-KEM-768 por defecto
195
- const ciphertext = await pqc.encrypt('hola post-quantum', pair.publicKey);
223
+ // Full roundtrip: generate keys, encrypt and decrypt.
224
+ const pair = await pqc.keys.generate(); // ML-KEM-768 by default
225
+ const ciphertext = await pqc.encrypt('hello post-quantum', pair.publicKey);
196
226
  const plaintext = await pqc.decrypt(ciphertext, pair.secretKey);
197
- console.log(new TextDecoder().decode(plaintext)); // "hola post-quantum"
227
+ console.log(new TextDecoder().decode(plaintext)); // "hello post-quantum"
198
228
 
199
- // Firmas digitales (ML-DSA-65):
229
+ // Digital signatures (ML-DSA-65):
200
230
  const signer = await pqc.keys.generate({ algorithm: 'ml-dsa-65' });
201
- const signature = await pqc.sign('documento', signer.secretKey);
202
- console.log(await pqc.verify('documento', signature, signer.publicKey)); // true
231
+ const signature = await pqc.sign('document', signer.secretKey);
232
+ console.log(await pqc.verify('document', signature, signer.publicKey)); // true
203
233
 
204
- // Las keys se serializan a base64url con metadata, listas para persistir:
234
+ // Keys serialize to base64url with metadata, ready to persist:
205
235
  const token = pqc.keys.serialize(pair.publicKey);
206
236
  console.log(token.slice(0, 48) + '\u2026');
207
237
 
208
- // Para cargar las keys de desarrollo que gener\xF3 \`pqc init\`:
238
+ // To load the development keys generated by \`pqc init\`:
209
239
  // import { readFile } from 'node:fs/promises';
210
240
  // const publicKey = pqc.keys.deserialize(
211
241
  // (await readFile('keys/dev.public.pqc', 'utf8')).trim(),
@@ -214,23 +244,23 @@ console.log(token.slice(0, 48) + '\u2026');
214
244
  var init = defineCommand2({
215
245
  meta: {
216
246
  name: "init",
217
- description: "Inicializa un proyecto: config, keys de desarrollo y ejemplo"
247
+ description: "Initialize a project: config, development keys and example"
218
248
  },
219
249
  async run() {
220
250
  if (existsSync3(CONFIG_FILE)) {
221
- throw new Error(`${CONFIG_FILE} ya existe: el proyecto ya est\xE1 inicializado.`);
251
+ throw new Error(`${CONFIG_FILE} already exists: the project is already initialized.`);
222
252
  }
223
253
  await writeFile2(CONFIG_FILE, `${JSON.stringify(CONFIG, null, 2)}
224
254
  `);
225
255
  const keys = await writeKeyPair(CONFIG.keysDir, "dev", CONFIG.defaultAlgorithm, false);
226
256
  await writeFile2("example.ts", EXAMPLE);
227
- heading("Proyecto PQC inicializado:");
228
- item(`${CONFIG_FILE} \u2014 configuraci\xF3n con defaults seguros`);
229
- item(`${keys.publicPath} / ${keys.secretPath} \u2014 par ${keys.algorithm} de desarrollo`);
230
- item("example.ts \u2014 roundtrip completo listo para ejecutar");
257
+ heading("PQC project initialized:");
258
+ item(`${CONFIG_FILE} \u2014 configuration with safe defaults`);
259
+ item(`${keys.publicPath} / ${keys.secretPath} \u2014 development ${keys.algorithm} pair`);
260
+ item("example.ts \u2014 full roundtrip ready to run");
231
261
  console.log();
232
- warn("Las keys de keys/dev.* son SOLO de desarrollo \u2014 NO usarlas en producci\xF3n.");
233
- ok(`Siguiente paso: ejecut\xE1 example.ts (node --experimental-strip-types example.ts o tsx)`);
262
+ warn("The keys/dev.* keys are for development ONLY \u2014 do NOT use them in production.");
263
+ ok(`Next step: run example.ts (node --experimental-strip-types example.ts or tsx)`);
234
264
  }
235
265
  });
236
266
 
@@ -239,32 +269,37 @@ import { defineCommand as defineCommand3 } from "citty";
239
269
  var keygen = defineCommand3({
240
270
  meta: {
241
271
  name: "keygen",
242
- description: "Genera un par de keys PQC serializadas en base64url"
272
+ description: "Generate a PQC key pair serialized as base64url"
243
273
  },
244
274
  args: {
245
275
  algorithm: {
246
276
  type: "string",
247
- description: "Algoritmo del par (ml-kem-768 o ml-dsa-65)",
277
+ description: "Algorithm of the pair (ml-kem-768 or ml-dsa-65)",
248
278
  default: "ml-kem-768"
249
279
  },
280
+ name: {
281
+ type: "string",
282
+ description: "Base file name for the key pair (default: the algorithm, e.g. ml-kem-768)"
283
+ },
250
284
  out: {
251
285
  type: "string",
252
- description: "Directorio de salida",
286
+ description: "Output directory",
253
287
  default: "keys"
254
288
  },
255
289
  force: {
256
290
  type: "boolean",
257
- description: "Sobreescribir keys existentes",
291
+ description: "Overwrite existing keys",
258
292
  default: false
259
293
  }
260
294
  },
261
295
  async run({ args }) {
262
296
  const algorithm = assertSupportedAlgorithm(args.algorithm);
263
- const keys = await writeKeyPair(args.out, algorithm, algorithm, args.force);
264
- ok(`Par ${algorithm} generado:`);
265
- item(`p\xFAblica: ${keys.publicPath}`);
266
- item(`secreta: ${keys.secretPath} (modo 0600)`);
267
- warn("La key secreta no debe commitearse ni salir de este entorno.");
297
+ const baseName = args.name === void 0 ? algorithm : assertSafeName(args.name);
298
+ const keys = await writeKeyPair(args.out, baseName, algorithm, args.force);
299
+ ok(`${algorithm} pair generated:`);
300
+ item(`public: ${keys.publicPath}`);
301
+ item(`secret: ${keys.secretPath} (mode 0600)`);
302
+ warn("The secret key must not be committed or leave this environment.");
268
303
  }
269
304
  });
270
305
 
@@ -272,8 +307,8 @@ var keygen = defineCommand3({
272
307
  var main = defineCommand4({
273
308
  meta: {
274
309
  name: "pqc",
275
- version: "0.1.1",
276
- description: "CLI del SDK de criptograf\xEDa post-cu\xE1ntica (@pqc-sdk/core)"
310
+ version: "0.2.0",
311
+ description: "CLI for the post-quantum cryptography SDK (@pqc-sdk/core)"
277
312
  },
278
313
  subCommands: {
279
314
  init,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/commands/audit.ts","../src/ui.ts","../src/commands/init.ts","../src/keyfiles.ts","../src/commands/keygen.ts"],"sourcesContent":["import { defineCommand, runMain } from 'citty';\n\nimport { audit } from './commands/audit.js';\nimport { init } from './commands/init.js';\nimport { keygen } from './commands/keygen.js';\n\n// Inyectada por tsup (`define` en tsup.config.ts) desde el package.json en build time.\ndeclare const __PQC_CLI_VERSION__: string;\n\nconst main = defineCommand({\n meta: {\n name: 'pqc',\n version: __PQC_CLI_VERSION__,\n description: 'CLI del SDK de criptografía post-cuántica (@pqc-sdk/core)',\n },\n subCommands: {\n init,\n keygen,\n audit,\n },\n});\n\nawait runMain(main);\n","import { readFile, readdir } from 'node:fs/promises';\nimport { existsSync } from 'node:fs';\nimport { join, relative } from 'node:path';\n\nimport { defineCommand } from 'citty';\nimport pc from 'picocolors';\n\nimport { finding, heading, ok } from '../ui.js';\n\ninterface Finding {\n location: string;\n what: string;\n migrateTo: string;\n}\n\nconst ML_DSA = 'ML-DSA-65 (pqc.sign / pqc.verify)';\nconst ML_KEM = 'ML-KEM-768 + AES-256-GCM (pqc.encrypt / pqc.decrypt)';\n\nconst RISKY_PACKAGES: Record<string, { what: string; migrateTo: string }> = {\n jsonwebtoken: { what: 'JWTs firmados con RSA/ECDSA (RS256/ES256)', migrateTo: ML_DSA },\n jose: { what: 'JOSE/JWT con algoritmos RSA/ECDSA', migrateTo: ML_DSA },\n elliptic: { what: 'Curvas elípticas clásicas (ECDSA/ECDH)', migrateTo: `${ML_DSA} y ${ML_KEM}` },\n secp256k1: { what: 'Firmas ECDSA sobre secp256k1', migrateTo: ML_DSA },\n 'node-rsa': { what: 'Cifrado y firmas RSA', migrateTo: `${ML_KEM} y ${ML_DSA}` },\n 'node-forge': { what: 'RSA/X.509 clásico', migrateTo: `${ML_KEM} y ${ML_DSA}` },\n tweetnacl: { what: 'Ed25519/X25519 (pre-cuántico)', migrateTo: `${ML_DSA} y ${ML_KEM}` },\n};\n\nconst CODE_PATTERNS: ReadonlyArray<{ re: RegExp; what: string; migrateTo: string }> = [\n {\n re: /create(?:Sign|Verify)\\s*\\(/,\n what: 'firma RSA/ECDSA vía node:crypto (createSign/createVerify)',\n migrateTo: ML_DSA,\n },\n {\n re: /createECDH\\s*\\(|\\.diffieHellman\\s*\\(/,\n what: 'intercambio de claves ECDH/DH',\n migrateTo: ML_KEM,\n },\n {\n re: /publicEncrypt\\s*\\(|privateDecrypt\\s*\\(/,\n what: 'cifrado RSA (publicEncrypt/privateDecrypt)',\n migrateTo: ML_KEM,\n },\n {\n re: /generateKeyPair(?:Sync)?\\s*\\(\\s*['\"](?:rsa|rsa-pss|dsa|ec|ed25519|ed448|x25519|x448)['\"]/,\n what: 'generación de keypair pre-cuántico',\n migrateTo: 'pqc.keys.generate (ML-KEM-768 para cifrado, ML-DSA-65 para firmas)',\n },\n {\n re: /['\"`](?:RS|ES|PS)(?:256|384|512)['\"`]/,\n what: 'JWT con algoritmo de firma RSA/ECDSA',\n migrateTo: ML_DSA,\n },\n {\n re: /['\"`](?:RSA-OAEP|ECDH|ECDSA)['\"`]/,\n what: 'WebCrypto con algoritmo pre-cuántico',\n migrateTo: `${ML_KEM} o ${ML_DSA}`,\n },\n];\n\nconst SOURCE_EXTENSIONS = new Set(['.js', '.mjs', '.cjs', '.ts', '.mts', '.cts', '.jsx', '.tsx']);\nconst IGNORED_DIRS = new Set(['node_modules', 'dist', 'build', 'coverage', '.git', '.next']);\n\nasync function collectSourceFiles(root: string): Promise<string[]> {\n const files: string[] = [];\n const pending = [root];\n while (pending.length > 0) {\n const dir = pending.pop()!;\n for (const entry of await readdir(dir, { withFileTypes: true })) {\n if (entry.isDirectory()) {\n if (!IGNORED_DIRS.has(entry.name)) pending.push(join(dir, entry.name));\n continue;\n }\n const dot = entry.name.lastIndexOf('.');\n if (dot !== -1 && SOURCE_EXTENSIONS.has(entry.name.slice(dot))) {\n files.push(join(dir, entry.name));\n }\n }\n }\n return files.sort();\n}\n\nasync function auditPackageJson(cwd: string): Promise<Finding[]> {\n const path = join(cwd, 'package.json');\n if (!existsSync(path)) return [];\n const manifest = JSON.parse(await readFile(path, 'utf8')) as Record<\n string,\n Record<string, string> | undefined\n >;\n const declared = {\n ...manifest.dependencies,\n ...manifest.devDependencies,\n ...manifest.peerDependencies,\n };\n return Object.keys(declared)\n .filter((name) => name in RISKY_PACKAGES)\n .map((name) => ({ location: `package.json (${name})`, ...RISKY_PACKAGES[name]! }));\n}\n\nasync function auditSources(cwd: string): Promise<Finding[]> {\n const findings: Finding[] = [];\n for (const file of await collectSourceFiles(cwd)) {\n const lines = (await readFile(file, 'utf8')).split('\\n');\n lines.forEach((line, index) => {\n for (const { re, what, migrateTo } of CODE_PATTERNS) {\n if (re.test(line)) {\n findings.push({ location: `${relative(cwd, file)}:${index + 1}`, what, migrateTo });\n }\n }\n });\n }\n return findings;\n}\n\nexport const audit = defineCommand({\n meta: {\n name: 'audit',\n description: 'Detecta crypto pre-cuántico y sugiere el equivalente PQC',\n },\n async run() {\n const cwd = process.cwd();\n const findings = [...(await auditPackageJson(cwd)), ...(await auditSources(cwd))];\n\n if (findings.length === 0) {\n ok('Sin crypto pre-cuántico detectado.');\n return;\n }\n\n heading(`Crypto pre-cuántico detectado (${findings.length} hallazgos):`);\n for (const f of findings) {\n finding(f.location, f.what, f.migrateTo);\n }\n console.log();\n console.log(\n pc.yellow(\n `${findings.length} usos a migrar. Guía de algoritmos: FIPS 203 (ML-KEM) cifrado, FIPS 204 (ML-DSA) firmas.`,\n ),\n );\n process.exitCode = 1;\n },\n});\n","import pc from 'picocolors';\n\n/**\n * Helpers de salida. picocolors desactiva los colores automáticamente cuando\n * no hay TTY (y NO_COLOR/FORCE_COLOR se respetan), así el output queda legible\n * en pipes y logs de CI sin códigos ANSI.\n */\nexport const ok = (message: string): void => {\n console.log(`${pc.green('✓')} ${message}`);\n};\n\nexport const warn = (message: string): void => {\n console.log(`${pc.yellow('⚠')} ${pc.yellow(message)}`);\n};\n\nexport const item = (message: string): void => {\n console.log(` ${message}`);\n};\n\nexport const finding = (location: string, what: string, migrateTo: string): void => {\n console.log(` ${pc.red('●')} ${pc.bold(location)} — ${what}`);\n console.log(` ${pc.dim('migrar a:')} ${pc.cyan(migrateTo)}`);\n};\n\nexport const heading = (message: string): void => {\n console.log(pc.bold(message));\n};\n","import { writeFile } from 'node:fs/promises';\nimport { existsSync } from 'node:fs';\n\nimport { defineCommand } from 'citty';\n\nimport { writeKeyPair } from '../keyfiles.js';\nimport { heading, item, ok, warn } from '../ui.js';\n\nconst CONFIG_FILE = 'pqc.config.json';\n\nconst CONFIG = {\n defaultAlgorithm: 'ml-kem-768',\n keysDir: 'keys',\n} as const;\n\nconst EXAMPLE = `import { pqc } from '@pqc-sdk/core';\n\n// Roundtrip completo: generar keys, cifrar y descifrar.\nconst pair = await pqc.keys.generate(); // ML-KEM-768 por defecto\nconst ciphertext = await pqc.encrypt('hola post-quantum', pair.publicKey);\nconst plaintext = await pqc.decrypt(ciphertext, pair.secretKey);\nconsole.log(new TextDecoder().decode(plaintext)); // \"hola post-quantum\"\n\n// Firmas digitales (ML-DSA-65):\nconst signer = await pqc.keys.generate({ algorithm: 'ml-dsa-65' });\nconst signature = await pqc.sign('documento', signer.secretKey);\nconsole.log(await pqc.verify('documento', signature, signer.publicKey)); // true\n\n// Las keys se serializan a base64url con metadata, listas para persistir:\nconst token = pqc.keys.serialize(pair.publicKey);\nconsole.log(token.slice(0, 48) + '…');\n\n// Para cargar las keys de desarrollo que generó \\`pqc init\\`:\n// import { readFile } from 'node:fs/promises';\n// const publicKey = pqc.keys.deserialize(\n// (await readFile('keys/dev.public.pqc', 'utf8')).trim(),\n// );\n`;\n\nexport const init = defineCommand({\n meta: {\n name: 'init',\n description: 'Inicializa un proyecto: config, keys de desarrollo y ejemplo',\n },\n async run() {\n if (existsSync(CONFIG_FILE)) {\n throw new Error(`${CONFIG_FILE} ya existe: el proyecto ya está inicializado.`);\n }\n\n await writeFile(CONFIG_FILE, `${JSON.stringify(CONFIG, null, 2)}\\n`);\n const keys = await writeKeyPair(CONFIG.keysDir, 'dev', CONFIG.defaultAlgorithm, false);\n await writeFile('example.ts', EXAMPLE);\n\n heading('Proyecto PQC inicializado:');\n item(`${CONFIG_FILE} — configuración con defaults seguros`);\n item(`${keys.publicPath} / ${keys.secretPath} — par ${keys.algorithm} de desarrollo`);\n item('example.ts — roundtrip completo listo para ejecutar');\n console.log();\n warn('Las keys de keys/dev.* son SOLO de desarrollo — NO usarlas en producción.');\n ok(`Siguiente paso: ejecutá example.ts (node --experimental-strip-types example.ts o tsx)`);\n },\n});\n","import { chmod, mkdir, writeFile } from 'node:fs/promises';\nimport { existsSync } from 'node:fs';\nimport { join } from 'node:path';\n\nimport { SUPPORTED_ALGORITHMS, pqc, type SupportedAlgorithm } from '@pqc-sdk/core';\n\nexport interface WrittenKeyPair {\n algorithm: SupportedAlgorithm;\n publicPath: string;\n secretPath: string;\n}\n\nexport function assertSupportedAlgorithm(value: string): SupportedAlgorithm {\n if (!(SUPPORTED_ALGORITHMS as readonly string[]).includes(value)) {\n throw new Error(\n `Algoritmo no soportado: ${value} (soportados: ${SUPPORTED_ALGORITHMS.join(', ')})`,\n );\n }\n return value as SupportedAlgorithm;\n}\n\n/** Genera un par y lo escribe serializado en base64url, un archivo por key. */\nexport async function writeKeyPair(\n directory: string,\n baseName: string,\n algorithm: SupportedAlgorithm,\n force: boolean,\n): Promise<WrittenKeyPair> {\n const publicPath = join(directory, `${baseName}.public.pqc`);\n const secretPath = join(directory, `${baseName}.secret.pqc`);\n\n if (!force) {\n for (const path of [publicPath, secretPath]) {\n if (existsSync(path)) {\n throw new Error(`${path} ya existe. Usá --force para sobreescribirla.`);\n }\n }\n }\n\n const pair = await pqc.keys.generate({ algorithm });\n await mkdir(directory, { recursive: true });\n await writeFile(publicPath, `${pqc.keys.serialize(pair.publicKey)}\\n`);\n await writeFile(secretPath, `${pqc.keys.serialize(pair.secretKey)}\\n`, { mode: 0o600 });\n await chmod(secretPath, 0o600);\n\n return { algorithm, publicPath, secretPath };\n}\n","import { defineCommand } from 'citty';\n\nimport { assertSupportedAlgorithm, writeKeyPair } from '../keyfiles.js';\nimport { item, ok, warn } from '../ui.js';\n\nexport const keygen = defineCommand({\n meta: {\n name: 'keygen',\n description: 'Genera un par de keys PQC serializadas en base64url',\n },\n args: {\n algorithm: {\n type: 'string',\n description: 'Algoritmo del par (ml-kem-768 o ml-dsa-65)',\n default: 'ml-kem-768',\n },\n out: {\n type: 'string',\n description: 'Directorio de salida',\n default: 'keys',\n },\n force: {\n type: 'boolean',\n description: 'Sobreescribir keys existentes',\n default: false,\n },\n },\n async run({ args }) {\n const algorithm = assertSupportedAlgorithm(args.algorithm);\n const keys = await writeKeyPair(args.out, algorithm, algorithm, args.force);\n\n ok(`Par ${algorithm} generado:`);\n item(`pública: ${keys.publicPath}`);\n item(`secreta: ${keys.secretPath} (modo 0600)`);\n warn('La key secreta no debe commitearse ni salir de este entorno.');\n },\n});\n"],"mappings":"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","names":["defineCommand","pc","pc","writeFile","existsSync","defineCommand","existsSync","join","defineCommand","existsSync","writeFile","defineCommand","defineCommand","defineCommand"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/commands/audit.ts","../src/ui.ts","../src/commands/init.ts","../src/keyfiles.ts","../src/commands/keygen.ts"],"sourcesContent":["import { defineCommand, runMain } from 'citty';\n\nimport { audit } from './commands/audit.js';\nimport { init } from './commands/init.js';\nimport { keygen } from './commands/keygen.js';\n\n// Injected by tsup (`define` in tsup.config.ts) from package.json at build time.\ndeclare const __PQC_CLI_VERSION__: string;\n\nconst main = defineCommand({\n meta: {\n name: 'pqc',\n version: __PQC_CLI_VERSION__,\n description: 'CLI for the post-quantum cryptography SDK (@pqc-sdk/core)',\n },\n subCommands: {\n init,\n keygen,\n audit,\n },\n});\n\nawait runMain(main);\n","import { readFile, readdir, stat } from 'node:fs/promises';\nimport { existsSync } from 'node:fs';\nimport { join, relative } from 'node:path';\n\nimport { defineCommand } from 'citty';\nimport pc from 'picocolors';\n\nimport { finding, heading, note, ok } from '../ui.js';\n\ninterface Finding {\n location: string;\n what: string;\n migrateTo: string;\n}\n\n/**\n * Upper bound on the size of a single source file the scanner will read. Files\n * larger than this are skipped: they are almost never hand-written source, and\n * reading them would slow the scan with no useful signal.\n */\nconst MAX_FILE_BYTES = 1024 * 1024; // 1 MiB\n\nconst ML_DSA = 'ML-DSA-65 (pqc.sign / pqc.verify)';\nconst ML_KEM = 'ML-KEM-768 + AES-256-GCM (pqc.encrypt / pqc.decrypt)';\n\nconst RISKY_PACKAGES: Record<string, { what: string; migrateTo: string }> = {\n jsonwebtoken: { what: 'JWTs signed with RSA/ECDSA (RS256/ES256)', migrateTo: ML_DSA },\n jose: { what: 'JOSE/JWT with RSA/ECDSA algorithms', migrateTo: ML_DSA },\n elliptic: { what: 'Classic elliptic curves (ECDSA/ECDH)', migrateTo: `${ML_DSA} and ${ML_KEM}` },\n secp256k1: { what: 'ECDSA signatures over secp256k1', migrateTo: ML_DSA },\n 'node-rsa': { what: 'RSA encryption and signatures', migrateTo: `${ML_KEM} and ${ML_DSA}` },\n 'node-forge': { what: 'Classic RSA/X.509', migrateTo: `${ML_KEM} and ${ML_DSA}` },\n tweetnacl: { what: 'Ed25519/X25519 (pre-quantum)', migrateTo: `${ML_DSA} and ${ML_KEM}` },\n};\n\nconst CODE_PATTERNS: ReadonlyArray<{ re: RegExp; what: string; migrateTo: string }> = [\n {\n re: /create(?:Sign|Verify)\\s*\\(/,\n what: 'RSA/ECDSA signing via node:crypto (createSign/createVerify)',\n migrateTo: ML_DSA,\n },\n {\n re: /createECDH\\s*\\(|\\.diffieHellman\\s*\\(/,\n what: 'ECDH/DH key exchange',\n migrateTo: ML_KEM,\n },\n {\n re: /publicEncrypt\\s*\\(|privateDecrypt\\s*\\(/,\n what: 'RSA encryption (publicEncrypt/privateDecrypt)',\n migrateTo: ML_KEM,\n },\n {\n re: /generateKeyPair(?:Sync)?\\s*\\(\\s*['\"](?:rsa|rsa-pss|dsa|ec|ed25519|ed448|x25519|x448)['\"]/,\n what: 'pre-quantum keypair generation',\n migrateTo: 'pqc.keys.generate (ML-KEM-768 for encryption, ML-DSA-65 for signatures)',\n },\n {\n re: /['\"`](?:RS|ES|PS)(?:256|384|512)['\"`]/,\n what: 'JWT with an RSA/ECDSA signing algorithm',\n migrateTo: ML_DSA,\n },\n {\n re: /['\"`](?:RSA-OAEP|ECDH|ECDSA)['\"`]/,\n what: 'WebCrypto with a pre-quantum algorithm',\n migrateTo: `${ML_KEM} or ${ML_DSA}`,\n },\n];\n\nconst SOURCE_EXTENSIONS = new Set(['.js', '.mjs', '.cjs', '.ts', '.mts', '.cts', '.jsx', '.tsx']);\nconst IGNORED_DIRS = new Set(['node_modules', 'dist', 'build', 'coverage', '.git', '.next']);\n\nasync function collectSourceFiles(root: string): Promise<string[]> {\n const files: string[] = [];\n const pending = [root];\n while (pending.length > 0) {\n const dir = pending.pop()!;\n for (const entry of await readdir(dir, { withFileTypes: true })) {\n if (entry.isDirectory()) {\n if (!IGNORED_DIRS.has(entry.name)) pending.push(join(dir, entry.name));\n continue;\n }\n const dot = entry.name.lastIndexOf('.');\n if (dot !== -1 && SOURCE_EXTENSIONS.has(entry.name.slice(dot))) {\n files.push(join(dir, entry.name));\n }\n }\n }\n return files.sort();\n}\n\nasync function auditPackageJson(cwd: string): Promise<Finding[]> {\n const path = join(cwd, 'package.json');\n if (!existsSync(path)) return [];\n const manifest = JSON.parse(await readFile(path, 'utf8')) as Record<\n string,\n Record<string, string> | undefined\n >;\n const declared = {\n ...manifest.dependencies,\n ...manifest.devDependencies,\n ...manifest.peerDependencies,\n };\n return Object.keys(declared)\n .filter((name) => name in RISKY_PACKAGES)\n .map((name) => ({ location: `package.json (${name})`, ...RISKY_PACKAGES[name]! }));\n}\n\ninterface SourceScan {\n findings: Finding[];\n /** Files skipped because they exceed {@link MAX_FILE_BYTES}, relative to cwd. */\n skipped: string[];\n}\n\nasync function auditSources(cwd: string): Promise<SourceScan> {\n const findings: Finding[] = [];\n const skipped: string[] = [];\n for (const file of await collectSourceFiles(cwd)) {\n if ((await stat(file)).size > MAX_FILE_BYTES) {\n skipped.push(relative(cwd, file));\n continue;\n }\n const lines = (await readFile(file, 'utf8')).split('\\n');\n lines.forEach((line, index) => {\n for (const { re, what, migrateTo } of CODE_PATTERNS) {\n if (re.test(line)) {\n findings.push({ location: `${relative(cwd, file)}:${index + 1}`, what, migrateTo });\n }\n }\n });\n }\n return { findings, skipped };\n}\n\nexport const audit = defineCommand({\n meta: {\n name: 'audit',\n description:\n 'Heuristically detect pre-quantum crypto (best-effort regex scan) and suggest the PQC equivalent',\n },\n async run() {\n const cwd = process.cwd();\n const { findings: sourceFindings, skipped } = await auditSources(cwd);\n const findings = [...(await auditPackageJson(cwd)), ...sourceFindings];\n\n note(\n 'Heuristic, best-effort regex scan — expect occasional false positives and false negatives.',\n );\n if (skipped.length > 0) {\n note(\n `Skipped ${skipped.length} file(s) larger than ${MAX_FILE_BYTES / 1024 / 1024} MiB: ${skipped.join(', ')}`,\n );\n }\n\n if (findings.length === 0) {\n ok('No pre-quantum crypto detected.');\n return;\n }\n\n heading(`Pre-quantum crypto detected (${findings.length} findings):`);\n for (const f of findings) {\n finding(f.location, f.what, f.migrateTo);\n }\n console.log();\n console.log(\n pc.yellow(\n `${findings.length} usages to migrate. Algorithm guide: FIPS 203 (ML-KEM) encryption, FIPS 204 (ML-DSA) signatures.`,\n ),\n );\n process.exitCode = 1;\n },\n});\n","import pc from 'picocolors';\n\n/**\n * Output helpers. picocolors disables colors automatically when there is no\n * TTY (and NO_COLOR/FORCE_COLOR are honored), so output stays readable in\n * pipes and CI logs without ANSI codes.\n */\nexport const ok = (message: string): void => {\n console.log(`${pc.green('✓')} ${message}`);\n};\n\nexport const warn = (message: string): void => {\n console.log(`${pc.yellow('⚠')} ${pc.yellow(message)}`);\n};\n\nexport const item = (message: string): void => {\n console.log(` ${message}`);\n};\n\nexport const finding = (location: string, what: string, migrateTo: string): void => {\n console.log(` ${pc.red('●')} ${pc.bold(location)} — ${what}`);\n console.log(` ${pc.dim('migrate to:')} ${pc.cyan(migrateTo)}`);\n};\n\nexport const heading = (message: string): void => {\n console.log(pc.bold(message));\n};\n\nexport const note = (message: string): void => {\n console.log(pc.dim(message));\n};\n","import { writeFile } from 'node:fs/promises';\nimport { existsSync } from 'node:fs';\n\nimport { defineCommand } from 'citty';\n\nimport { writeKeyPair } from '../keyfiles.js';\nimport { heading, item, ok, warn } from '../ui.js';\n\nconst CONFIG_FILE = 'pqc.config.json';\n\nconst CONFIG = {\n defaultAlgorithm: 'ml-kem-768',\n keysDir: 'keys',\n} as const;\n\nconst EXAMPLE = `import { pqc } from '@pqc-sdk/core';\n\n// Full roundtrip: generate keys, encrypt and decrypt.\nconst pair = await pqc.keys.generate(); // ML-KEM-768 by default\nconst ciphertext = await pqc.encrypt('hello post-quantum', pair.publicKey);\nconst plaintext = await pqc.decrypt(ciphertext, pair.secretKey);\nconsole.log(new TextDecoder().decode(plaintext)); // \"hello post-quantum\"\n\n// Digital signatures (ML-DSA-65):\nconst signer = await pqc.keys.generate({ algorithm: 'ml-dsa-65' });\nconst signature = await pqc.sign('document', signer.secretKey);\nconsole.log(await pqc.verify('document', signature, signer.publicKey)); // true\n\n// Keys serialize to base64url with metadata, ready to persist:\nconst token = pqc.keys.serialize(pair.publicKey);\nconsole.log(token.slice(0, 48) + '…');\n\n// To load the development keys generated by \\`pqc init\\`:\n// import { readFile } from 'node:fs/promises';\n// const publicKey = pqc.keys.deserialize(\n// (await readFile('keys/dev.public.pqc', 'utf8')).trim(),\n// );\n`;\n\nexport const init = defineCommand({\n meta: {\n name: 'init',\n description: 'Initialize a project: config, development keys and example',\n },\n async run() {\n if (existsSync(CONFIG_FILE)) {\n throw new Error(`${CONFIG_FILE} already exists: the project is already initialized.`);\n }\n\n await writeFile(CONFIG_FILE, `${JSON.stringify(CONFIG, null, 2)}\\n`);\n const keys = await writeKeyPair(CONFIG.keysDir, 'dev', CONFIG.defaultAlgorithm, false);\n await writeFile('example.ts', EXAMPLE);\n\n heading('PQC project initialized:');\n item(`${CONFIG_FILE} — configuration with safe defaults`);\n item(`${keys.publicPath} / ${keys.secretPath} — development ${keys.algorithm} pair`);\n item('example.ts — full roundtrip ready to run');\n console.log();\n warn('The keys/dev.* keys are for development ONLY — do NOT use them in production.');\n ok(`Next step: run example.ts (node --experimental-strip-types example.ts or tsx)`);\n },\n});\n","import { chmod, mkdir, writeFile } from 'node:fs/promises';\nimport { existsSync } from 'node:fs';\nimport { join } from 'node:path';\n\nimport { SUPPORTED_ALGORITHMS, pqc, type SupportedAlgorithm } from '@pqc-sdk/core';\n\nexport interface WrittenKeyPair {\n algorithm: SupportedAlgorithm;\n publicPath: string;\n secretPath: string;\n}\n\nexport function assertSupportedAlgorithm(value: string): SupportedAlgorithm {\n if (!(SUPPORTED_ALGORITHMS as readonly string[]).includes(value)) {\n throw new Error(\n `Unsupported algorithm: ${value} (supported: ${SUPPORTED_ALGORITHMS.join(', ')})`,\n );\n }\n return value as SupportedAlgorithm;\n}\n\n/**\n * Validates a base file name for a key pair. The name becomes part of the path\n * passed to {@link writeKeyPair}, so it must not be empty, contain path\n * separators (`/` or `\\`), or contain `..` — otherwise a caller could write\n * keys outside the intended output directory.\n */\nexport function assertSafeName(value: string): string {\n if (value === '') {\n throw new Error('Invalid --name: must not be empty.');\n }\n if (value.includes('/') || value.includes('\\\\')) {\n throw new Error('Invalid --name: must not contain path separators (\"/\" or \"\\\\\").');\n }\n if (value.includes('..')) {\n throw new Error('Invalid --name: must not contain \"..\".');\n }\n return value;\n}\n\n/** Generates a pair and writes it serialized as base64url, one file per key. */\nexport async function writeKeyPair(\n directory: string,\n baseName: string,\n algorithm: SupportedAlgorithm,\n force: boolean,\n): Promise<WrittenKeyPair> {\n const publicPath = join(directory, `${baseName}.public.pqc`);\n const secretPath = join(directory, `${baseName}.secret.pqc`);\n\n if (!force) {\n for (const path of [publicPath, secretPath]) {\n if (existsSync(path)) {\n throw new Error(`${path} already exists. Use --force to overwrite it.`);\n }\n }\n }\n\n const pair = await pqc.keys.generate({ algorithm });\n await mkdir(directory, { recursive: true });\n await writeFile(publicPath, `${pqc.keys.serialize(pair.publicKey)}\\n`);\n await writeFile(secretPath, `${pqc.keys.serialize(pair.secretKey)}\\n`, { mode: 0o600 });\n await chmod(secretPath, 0o600);\n\n return { algorithm, publicPath, secretPath };\n}\n","import { defineCommand } from 'citty';\n\nimport { assertSafeName, assertSupportedAlgorithm, writeKeyPair } from '../keyfiles.js';\nimport { item, ok, warn } from '../ui.js';\n\nexport const keygen = defineCommand({\n meta: {\n name: 'keygen',\n description: 'Generate a PQC key pair serialized as base64url',\n },\n args: {\n algorithm: {\n type: 'string',\n description: 'Algorithm of the pair (ml-kem-768 or ml-dsa-65)',\n default: 'ml-kem-768',\n },\n name: {\n type: 'string',\n description: 'Base file name for the key pair (default: the algorithm, e.g. ml-kem-768)',\n },\n out: {\n type: 'string',\n description: 'Output directory',\n default: 'keys',\n },\n force: {\n type: 'boolean',\n description: 'Overwrite existing keys',\n default: false,\n },\n },\n async run({ args }) {\n const algorithm = assertSupportedAlgorithm(args.algorithm);\n const baseName = args.name === undefined ? algorithm : assertSafeName(args.name);\n const keys = await writeKeyPair(args.out, baseName, algorithm, args.force);\n\n ok(`${algorithm} pair generated:`);\n item(`public: ${keys.publicPath}`);\n item(`secret: ${keys.secretPath} (mode 0600)`);\n warn('The secret key must not be committed or leave this environment.');\n },\n});\n"],"mappings":"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","names":["defineCommand","pc","pc","writeFile","existsSync","defineCommand","existsSync","join","defineCommand","existsSync","writeFile","defineCommand","defineCommand","defineCommand"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pqc-sdk/cli",
3
- "version": "0.1.1",
4
- "description": "CLI del SDK de criptografía post-cuántica",
3
+ "version": "0.2.0",
4
+ "description": "CLI for the post-quantum cryptography SDK",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "pqc": "./dist/index.js"
@@ -15,7 +15,7 @@
15
15
  "dependencies": {
16
16
  "citty": "^0.2.2",
17
17
  "picocolors": "^1.1.1",
18
- "@pqc-sdk/core": "0.1.1"
18
+ "@pqc-sdk/core": "0.2.0"
19
19
  },
20
20
  "devDependencies": {
21
21
  "@types/node": "^22.15.29",
@@ -23,7 +23,7 @@
23
23
  "vitest": "^3.2.6"
24
24
  },
25
25
  "license": "MIT",
26
- "homepage": "https://github.com/jeloercc/pqc-sdk#readme",
26
+ "homepage": "https://jeloercc.github.io/pqc-sdk/",
27
27
  "bugs": "https://github.com/jeloercc/pqc-sdk/issues",
28
28
  "publishConfig": {
29
29
  "access": "public"