@pasosdejesus/m 0.32.0 → 0.34.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.
@@ -1,5 +1,6 @@
1
1
  import * as fs from 'fs';
2
2
  import * as path from 'path';
3
+ import { spawnSync } from 'node:child_process';
3
4
  import { fileURLToPath } from 'url';
4
5
  import { dirname } from 'path';
5
6
  import { problem, success } from '../util/colors.js';
@@ -14,14 +15,25 @@ const t = createTranslator(detectLocale(), {
14
15
  'create.file_added': 'Added {{0}}',
15
16
  'create.error': 'Error creating project: {{0}}',
16
17
  'create.done': 'Project created successfully.',
18
+ 'create.pnpm_missing': 'pnpm is not in PATH. Generated projects use pnpm {{0}}: install it with `npm i -g pnpm@{{0}}` (or `corepack enable`).',
17
19
  },
18
20
  es: {
19
21
  'create.generating': 'Generando proyecto en {{0}}...',
20
22
  'create.file_added': 'Agregado {{0}}',
21
23
  'create.error': 'Error al crear el proyecto: {{0}}',
22
24
  'create.done': 'Proyecto creado exitosamente.',
25
+ 'create.pnpm_missing': 'pnpm no está en PATH. Los proyectos generados usan pnpm {{0}}: instálalo con `npm i -g pnpm@{{0}}` (o `corepack enable`).',
23
26
  },
24
27
  }, commonCli);
28
+ function templatePnpmVersion() {
29
+ try {
30
+ const pkg = JSON.parse(fs.readFileSync(path.join(getTemplateDir(), 'package.json.hbs'), 'utf-8'));
31
+ return String(pkg.packageManager ?? 'pnpm@11').replace(/^pnpm@/, '');
32
+ }
33
+ catch {
34
+ return '11';
35
+ }
36
+ }
25
37
  function getTemplateDir() {
26
38
  // __dirname is dist/tasks/ in the npm package; dist/templates/ is where build copies templates
27
39
  const distTemplates = path.join(__dirname, '..', 'templates');
@@ -188,6 +200,10 @@ export async function runCreateProject(name, description, baseDir) {
188
200
  const templateDir = getTemplateDir();
189
201
  const cwd = baseDir ?? process.cwd();
190
202
  const destDir = path.resolve(cwd, name);
203
+ if (spawnSync('pnpm', ['--version'], { stdio: 'ignore' }).status !== 0) {
204
+ problem(t('create.pnpm_missing', templatePnpmVersion()));
205
+ process.exit(1);
206
+ }
191
207
  if (fs.existsSync(destDir)) {
192
208
  problem(t('create.error', `Directory ${name} already exists`));
193
209
  process.exit(1);
@@ -1 +1 @@
1
- {"version":3,"file":"create.js","sourceRoot":"","sources":["../../src/tasks/create.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAA;AACxB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAA;AAC5B,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAA;AACnC,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAC9B,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAA;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAA;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAChD,OAAO,SAAS,MAAM,uBAAuB,CAAA;AAE7C,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AACjD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAA;AAErC,MAAM,CAAC,GAAG,gBAAgB,CAAC,YAAY,EAAE,EAAE;IACzC,EAAE,EAAE;QACF,mBAAmB,EAAE,gCAAgC;QACrD,mBAAmB,EAAE,aAAa;QAClC,cAAc,EAAE,+BAA+B;QAC/C,aAAa,EAAE,+BAA+B;KAC/C;IACD,EAAE,EAAE;QACF,mBAAmB,EAAE,gCAAgC;QACrD,mBAAmB,EAAE,gBAAgB;QACrC,cAAc,EAAE,mCAAmC;QACnD,aAAa,EAAE,+BAA+B;KAC/C;CACF,EAAE,SAAS,CAAC,CAAA;AAEb,SAAS,cAAc;IACrB,+FAA+F;IAC/F,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,WAAW,CAAC,CAAA;IAC7D,IAAI,EAAE,CAAC,UAAU,CAAC,aAAa,CAAC;QAAE,OAAO,aAAa,CAAA;IACtD,mDAAmD;IACnD,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,CAAC,CAAA;IAClE,IAAI,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC;QAAE,OAAO,YAAY,CAAA;IACpD,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,WAAW,CAAC,CAAA;AAC1C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,MAAM,CAAC,OAAe,EAAE,IAAY,EAAE,WAAmB;IACvE,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,GAAG,CAAC,oBAAoB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,CAAC,CAAA;IAChG,OAAO,OAAO;SACX,OAAO,CAAC,eAAe,EAAE,IAAI,CAAC;SAC9B,OAAO,CAAC,sBAAsB,EAAE,WAAW,CAAC;SAC5C,OAAO,CAAC,oBAAoB,EAAE,GAAG,CAAC,OAAO,CAAC,CAAA;AAC/C,CAAC;AAED,SAAS,WAAW,CAAC,GAAW;IAC9B,MAAM,KAAK,GAAa,EAAE,CAAA;IAC1B,MAAM,OAAO,GAAG,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAA;IAC5D,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAA;QAC3C,IAAI,KAAK,CAAC,IAAI,KAAK,gBAAgB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;YAAE,SAAQ;QAC1H,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;YACxB,KAAK,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAA;QACtC,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QACtB,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED,SAAS,UAAU,CAAC,OAAe,EAAE,IAAY;IAC/C,OAAO,OAAO,CAAC,OAAO,CAAC,eAAe,EAAE,IAAI,CAAC,CAAA;AAC/C,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAAY;IAChD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAA;IACzB,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,CAAC,CAAA;IAC9C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,CAAA;IAE5C,IAAI,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QAC3B,OAAO,CAAC,CAAC,CAAC,cAAc,EAAE,UAAU,IAAI,iBAAiB,CAAC,CAAC,CAAA;QAC3D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;IAED,MAAM,KAAK,GAA2B;QACpC,eAAe,EAAE,UAAU,CAAC;;;;CAI/B,EAAE,IAAI,CAAC;QACJ,cAAc,EAAE,UAAU,CAAC;;;;;;;;;;;;;;;;;;;CAmB9B,EAAE,IAAI,CAAC;QACJ,eAAe,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4BpB;QACG,0BAA0B,EAAE;;;;;;;;;;;;;;;;;;;;;CAqB/B;QACG,cAAc,EAAE;;;;;;;;;;;;;;CAcnB;QACG,wBAAwB,EAAE,EAAE;QAC5B,qBAAqB,EAAE,EAAE;QACzB,yBAAyB,EAAE,EAAE;QAC7B,kBAAkB,EAAE,EAAE;QACtB,iBAAiB,EAAE,EAAE;QACrB,eAAe,EAAE,EAAE;KACpB,CAAA;IAED,KAAK,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACvD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;QAC5C,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QACzD,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,CAAA;QAC5C,OAAO,CAAC,CAAC,CAAC,mBAAmB,EAAE,YAAY,IAAI,IAAI,OAAO,EAAE,CAAC,CAAC,CAAA;IAChE,CAAC;IAED,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAA;AAC3B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,IAAY,EAAE,WAAoB,EAAE,OAAgB;IACzF,MAAM,IAAI,GAAG,WAAW,IAAI,EAAE,CAAA;IAC9B,MAAM,WAAW,GAAG,cAAc,EAAE,CAAA;IACpC,MAAM,GAAG,GAAG,OAAO,IAAI,OAAO,CAAC,GAAG,EAAE,CAAA;IACpC,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;IAEvC,IAAI,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QAC3B,OAAO,CAAC,CAAC,CAAC,cAAc,EAAE,aAAa,IAAI,iBAAiB,CAAC,CAAC,CAAA;QAC9D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;IAED,MAAM,QAAQ,GAAG,WAAW,CAAC,WAAW,CAAC,CAAA;IACzC,MAAM,YAAY,GAAG,WAAW,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;IAEpD,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAA;QAC9E,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,CAAA;QAEhD,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QAEzD,IAAI,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YAC7B,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;YACjD,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,CAAA;YAC5C,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAA;QAC/C,CAAC;aAAM,CAAC;YACN,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAA;QACpC,CAAC;QAED,OAAO,CAAC,CAAC,CAAC,mBAAmB,EAAE,GAAG,GAAG,WAAW,CAAC,CAAC,CAAA;IACpD,CAAC;IAED,wBAAwB;IACxB,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,CAAC,CAAA;IAC1D,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACxB,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;QACzB,OAAO,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,CAAC,aAAa,CAAC,CAAA;IAC1E,CAAC;IAED,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAA;AAC3B,CAAC"}
1
+ {"version":3,"file":"create.js","sourceRoot":"","sources":["../../src/tasks/create.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ export interface RenamedEnvVar {
2
+ from: string;
3
+ to: string;
4
+ }
5
+ export declare const RENAMED_ENV_VARS: readonly RenamedEnvVar[];
6
+ export declare function renamedFindings(text: string): RenamedEnvVar[];
7
+ export declare function envFilesFrom(start: string, levels?: number): string[];
8
+ /**
9
+ * `env:check` — warns about environment variables renamed in this ecosystem
10
+ * (REQ/51). Informative only: it never changes the exit code, so `make all`
11
+ * keeps building.
12
+ */
13
+ export declare function runEnvCheck(args?: string[]): Promise<void>;
14
+ //# sourceMappingURL=env-check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env-check.d.ts","sourceRoot":"","sources":["../../src/tasks/env-check.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,EAAE,EAAE,MAAM,CAAA;CACX;AAED,eAAO,MAAM,gBAAgB,EAAE,SAAS,aAAa,EAGpD,CAAA;AAaD,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,EAAE,CAG7D;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,SAAI,GAAG,MAAM,EAAE,CAWhE;AAED;;;;GAIG;AACH,wBAAsB,WAAW,CAAC,IAAI,GAAE,MAAM,EAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAgCpE"}
@@ -0,0 +1,77 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { info, warn } from '../util/colors.js';
4
+ export const RENAMED_ENV_VARS = [
5
+ { from: 'NEXT_PUBLIC_SLEARN_ADDRESS', to: 'NEXT_PUBLIC_SLEARN_TESTNET' },
6
+ { from: 'NEXT_PUBLIC_USDT_ADDRESS', to: 'NEXT_PUBLIC_USDT_TESTNET' },
7
+ ];
8
+ function definedKeys(text) {
9
+ const keys = new Set();
10
+ for (const rawLine of text.split(/\r?\n/)) {
11
+ const line = rawLine.trim();
12
+ if (!line || line.startsWith('#'))
13
+ continue;
14
+ const match = line.match(/^(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=/);
15
+ if (match)
16
+ keys.add(match[1]);
17
+ }
18
+ return keys;
19
+ }
20
+ export function renamedFindings(text) {
21
+ const keys = definedKeys(text);
22
+ return RENAMED_ENV_VARS.filter((entry) => keys.has(entry.from));
23
+ }
24
+ export function envFilesFrom(start, levels = 3) {
25
+ const files = [];
26
+ let current = path.resolve(start);
27
+ for (let index = 0; index <= levels; index += 1) {
28
+ const candidate = path.join(current, '.env');
29
+ if (fs.existsSync(candidate))
30
+ files.push(candidate);
31
+ const parent = path.dirname(current);
32
+ if (parent === current)
33
+ break;
34
+ current = parent;
35
+ }
36
+ return files;
37
+ }
38
+ /**
39
+ * `env:check` — warns about environment variables renamed in this ecosystem
40
+ * (REQ/51). Informative only: it never changes the exit code, so `make all`
41
+ * keeps building.
42
+ */
43
+ export async function runEnvCheck(args = []) {
44
+ const explicit = args.filter((arg) => !arg.startsWith('-'));
45
+ const files = explicit.length > 0
46
+ ? explicit.map((file) => path.resolve(file)).filter((file) => fs.existsSync(file))
47
+ : envFilesFrom(process.cwd());
48
+ const reported = new Set();
49
+ const report = (entry, source) => {
50
+ if (reported.has(entry.from))
51
+ return;
52
+ reported.add(entry.from);
53
+ warn(` [WARN] ${entry.from} → ${entry.to} (${source}): el nombre viejo ya no se usa; sin la nueva variable se aplica el valor por omisión del ecosistema.`);
54
+ };
55
+ for (const file of files) {
56
+ let text = '';
57
+ try {
58
+ text = fs.readFileSync(file, 'utf-8');
59
+ }
60
+ catch {
61
+ continue;
62
+ }
63
+ for (const entry of renamedFindings(text))
64
+ report(entry, file);
65
+ }
66
+ for (const entry of RENAMED_ENV_VARS) {
67
+ if (process.env[entry.from] !== undefined)
68
+ report(entry, 'entorno');
69
+ }
70
+ if (reported.size === 0) {
71
+ info(' [OK] sin variables de entorno renombradas');
72
+ }
73
+ else {
74
+ info(' env:check es informativo: renombra las variables para fijar el valor explícitamente.');
75
+ }
76
+ }
77
+ //# sourceMappingURL=env-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env-check.js","sourceRoot":"","sources":["../../src/tasks/env-check.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ export interface ManCommand {
2
+ description: string;
3
+ argRequired?: boolean;
4
+ argOptional?: boolean;
5
+ argName?: string;
6
+ }
7
+ export interface ManCatalog {
8
+ commands: Record<string, ManCommand>;
9
+ categories: Record<string, string[]>;
10
+ }
11
+ export declare function generateMdoc(catalog: ManCatalog, version: string, date?: Date): string;
12
+ export declare function runMan(catalog: ManCatalog, args?: string[]): Promise<void>;
13
+ //# sourceMappingURL=man.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"man.d.ts","sourceRoot":"","sources":["../../src/tasks/man.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;IACpC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAA;CACrC;AA0BD,wBAAgB,YAAY,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,OAAa,GAAG,MAAM,CAoE5F;AAED,wBAAsB,MAAM,CAAC,OAAO,EAAE,UAAU,EAAE,IAAI,GAAE,MAAM,EAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAcpF"}
@@ -0,0 +1,82 @@
1
+ import fs from 'fs';
2
+ import { parseFlags } from '../util/cli-parser.js';
3
+ import { info, success } from '../util/colors.js';
4
+ function esc(text) {
5
+ const escaped = text.replace(/\\/g, '\\e').replace(/OpenBSD/g, 'Open\\&BSD');
6
+ return escaped.startsWith('.') || escaped.startsWith("'") ? `\\&${escaped}` : escaped;
7
+ }
8
+ const bytes = (text) => Buffer.byteLength(text, 'utf-8');
9
+ function wrap(text, width = 72) {
10
+ const words = text.split(/\s+/).filter(Boolean);
11
+ const lines = [];
12
+ let line = '';
13
+ for (const word of words) {
14
+ if (!line)
15
+ line = word;
16
+ else if (bytes(line) + 1 + bytes(word) <= width)
17
+ line += ` ${word}`;
18
+ else {
19
+ lines.push(line);
20
+ line = word;
21
+ }
22
+ }
23
+ if (line)
24
+ lines.push(line);
25
+ return lines;
26
+ }
27
+ function textLines(text) {
28
+ return text.split(/(?<=[.!?])\s+/).flatMap((sentence) => wrap(esc(sentence)));
29
+ }
30
+ export function generateMdoc(catalog, version, date = new Date()) {
31
+ const dd = date.toLocaleDateString('en-US', { month: 'long', day: 'numeric', year: 'numeric' }).replace(',', '');
32
+ const lines = [
33
+ '.\\" $OpenBSD$',
34
+ `.Dd $Mdocdate: ${dd} $`,
35
+ '.Dt M 1',
36
+ '.Os',
37
+ '.Sh NAME',
38
+ '.Nm m',
39
+ '.Nd CLI for Next.js and Hardhat projects',
40
+ '.Sh SYNOPSIS',
41
+ '.Nm',
42
+ '.Op Fl Vh',
43
+ '.Ar command',
44
+ '.Op Ar args ...',
45
+ '.Sh DESCRIPTION',
46
+ 'The',
47
+ '.Nm',
48
+ ...textLines('command scaffolds and manages integrated Next.js and Hardhat applications: projects (m:create, m:update, m:check), databases, engines, wallets, end-to-end tests and environment checks.'),
49
+ '.Sh COMMANDS',
50
+ ];
51
+ for (const [category, names] of Object.entries(catalog.categories)) {
52
+ const present = names.filter((name) => catalog.commands[name]);
53
+ if (present.length === 0)
54
+ continue;
55
+ lines.push(`.Ss ${category}`, '.Bl -tag -width Ds');
56
+ for (const name of present) {
57
+ const command = catalog.commands[name];
58
+ let head = `.It Cm ${name}`;
59
+ if (command.argRequired)
60
+ head += ` Ar ${command.argName ?? 'name'}`;
61
+ else if (command.argOptional)
62
+ head += ` Op Ar ${command.argName ?? 'output'}`;
63
+ lines.push(head, ...textLines(command.description));
64
+ }
65
+ lines.push('.El');
66
+ }
67
+ lines.push('.Sh ENVIRONMENT', '.Bl -tag -width Ds', '.It Ev PGUSER , Ev PGPASSWORD , Ev PGDATABASE', 'PostgreSQL connection for the database commands and the test project.', '.It Ev E2E_RETRIES', 'Default retry count for', '.Cm test:e2e .', '.It Ev E2E_LOG_DIR', 'Directory for the E2E logs (default', '.Pa /tmp ) .', '.It Ev E2E_SPEC_DELAY_MS', 'Delay between specs during an E2E run.', '.El', '.Sh FILES', '.Bl -tag -width Ds', '.It Pa .env', 'Project environment (consumers keep it in', '.Pa apps/.env ) .', '.It Pa ~/.m/wallets/', 'Encrypted operator wallets written by', '.Cm eng:opwallet:* .', '.It Pa m-extensions/', 'Project-specific hooks loaded by the CLI.', '.El', '.Sh EXIT STATUS', '.Ex -std', '.Sh SEE ALSO', '.Xr sh 1');
68
+ return `${lines.join('\n')}\n`;
69
+ }
70
+ export async function runMan(catalog, args = []) {
71
+ const { options } = parseFlags(args, { out: { type: 'string' } });
72
+ const pkg = JSON.parse(fs.readFileSync(new URL('../../package.json', import.meta.url), 'utf-8'));
73
+ const mdoc = generateMdoc(catalog, pkg.version ?? '0.0.0');
74
+ if (typeof options.out === 'string' && options.out.length > 0) {
75
+ fs.writeFileSync(options.out, mdoc);
76
+ success(`Man page written to ${options.out}`);
77
+ return;
78
+ }
79
+ info('Man page (mdoc):');
80
+ console.log(mdoc);
81
+ }
82
+ //# sourceMappingURL=man.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"man.js","sourceRoot":"","sources":["../../src/tasks/man.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAA;AAEnB,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;AAClD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAA;AAcjD,SAAS,GAAG,CAAC,IAAY;IACvB,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,YAAY,CAAC,CAAA;IAC5E,OAAO,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,OAAO,EAAE,CAAC,CAAC,CAAC,OAAO,CAAA;AACvF,CAAC;AAED,MAAM,KAAK,GAAG,CAAC,IAAY,EAAU,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;AAExE,SAAS,IAAI,CAAC,IAAY,EAAE,KAAK,GAAG,EAAE;IACpC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;IAC/C,MAAM,KAAK,GAAa,EAAE,CAAA;IAC1B,IAAI,IAAI,GAAG,EAAE,CAAA;IACb,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,IAAI;YAAE,IAAI,GAAG,IAAI,CAAA;aACjB,IAAI,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,KAAK;YAAE,IAAI,IAAI,IAAI,IAAI,EAAE,CAAA;aAC9D,CAAC;YAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAAC,IAAI,GAAG,IAAI,CAAA;QAAC,CAAC;IACxC,CAAC;IACD,IAAI,IAAI;QAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAC1B,OAAO,KAAK,CAAA;AACd,CAAC;AAED,SAAS,SAAS,CAAC,IAAY;IAC7B,OAAO,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAA;AAC/E,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,OAAmB,EAAE,OAAe,EAAE,IAAI,GAAG,IAAI,IAAI,EAAE;IAClF,MAAM,EAAE,GAAG,IAAI,CAAC,kBAAkB,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAA;IAChH,MAAM,KAAK,GAAa;QACtB,gBAAgB;QAChB,kBAAkB,EAAE,IAAI;QACxB,SAAS;QACT,KAAK;QACL,UAAU;QACV,OAAO;QACP,0CAA0C;QAC1C,cAAc;QACd,KAAK;QACL,WAAW;QACX,aAAa;QACb,iBAAiB;QACjB,iBAAiB;QACjB,KAAK;QACL,KAAK;QACL,GAAG,SAAS,CAAC,0LAA0L,CAAC;QACxM,cAAc;KACf,CAAA;IAED,KAAK,MAAM,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;QACnE,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAA;QAC9D,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,SAAQ;QAClC,KAAK,CAAC,IAAI,CAAC,OAAO,QAAQ,EAAE,EAAE,oBAAoB,CAAC,CAAA;QACnD,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC;YAC3B,MAAM,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;YACtC,IAAI,IAAI,GAAG,UAAU,IAAI,EAAE,CAAA;YAC3B,IAAI,OAAO,CAAC,WAAW;gBAAE,IAAI,IAAI,OAAO,OAAO,CAAC,OAAO,IAAI,MAAM,EAAE,CAAA;iBAC9D,IAAI,OAAO,CAAC,WAAW;gBAAE,IAAI,IAAI,UAAU,OAAO,CAAC,OAAO,IAAI,QAAQ,EAAE,CAAA;YAC7E,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,SAAS,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAA;QACrD,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IACnB,CAAC;IAED,KAAK,CAAC,IAAI,CACR,iBAAiB,EACjB,oBAAoB,EACpB,+CAA+C,EAC/C,uEAAuE,EACvE,oBAAoB,EACpB,yBAAyB,EACzB,gBAAgB,EAChB,oBAAoB,EACpB,qCAAqC,EACrC,cAAc,EACd,0BAA0B,EAC1B,wCAAwC,EACxC,KAAK,EACL,WAAW,EACX,oBAAoB,EACpB,aAAa,EACb,2CAA2C,EAC3C,mBAAmB,EACnB,sBAAsB,EACtB,uCAAuC,EACvC,sBAAsB,EACtB,sBAAsB,EACtB,2CAA2C,EAC3C,KAAK,EACL,iBAAiB,EACjB,UAAU,EACV,cAAc,EACd,UAAU,CACX,CAAA;IAED,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAA;AAChC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,OAAmB,EAAE,OAAiB,EAAE;IACnE,MAAM,EAAE,OAAO,EAAE,GAAG,UAAU,CAAC,IAAI,EAAE,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAA;IACjE,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,GAAG,CAAC,oBAAoB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,CAE9F,CAAA;IACD,MAAM,IAAI,GAAG,YAAY,CAAC,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,OAAO,CAAC,CAAA;IAE1D,IAAI,OAAO,OAAO,CAAC,GAAG,KAAK,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9D,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;QACnC,OAAO,CAAC,uBAAuB,OAAO,CAAC,GAAG,EAAE,CAAC,CAAA;QAC7C,OAAM;IACR,CAAC;IACD,IAAI,CAAC,kBAAkB,CAAC,CAAA;IACxB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;AACnB,CAAC"}
@@ -1,12 +1,16 @@
1
- .PHONY: all install build test type check update-skills
1
+ .PHONY: all install env-check build test type check update-skills
2
2
 
3
3
  # `all` vive en la raíz del workspace: una sola instalación para todas las apps.
4
4
  # [REQ/51](https://gitlab.com/pasosdeJesus/m/-/work_items/51) sumará aquí `./apps/web/bin/m env:check`.
5
- all: install build
5
+ all: install env-check build
6
6
 
7
7
  install:
8
8
  pnpm i
9
9
 
10
+ # Avisos de variables de entorno renombradas (informativo, no falla).
11
+ env-check:
12
+ @./apps/web/bin/m env:check || true
13
+
10
14
  # Next 16 con Webpack: V8 crashea (Trace/BPT trap) con el límite de data por
11
15
  # defecto en adJ/OpenBSD, así que el build sube a 7G.
12
16
  build:
@@ -29,7 +29,8 @@ doas pkg_add node
29
29
  npm install -g pnpm@11
30
30
  ```
31
31
 
32
- If using Hardhat on OpenBSD/adJ, run the preparation script:
32
+ If using Hardhat on OpenBSD/adJ, run the preparation script (it needs `doas corepack enable` once and
33
+ Rust/cargo to build the analyzer addon):
33
34
 
34
35
  ```bash
35
36
  cd apps/contracts && bin/prepadJ.sh
@@ -68,7 +68,10 @@ NEXT_PUBLIC_RPC_URL="https://lb.drpc.org/celo-sepolia/x"
68
68
  # -- Contract Addresses & Details --
69
69
  # Contract deployment variables (used by Hardhat scripts and sync-abis.mjs)
70
70
  NEXT_PUBLIC_DEPLOYED_AT=
71
- NEXT_PUBLIC_USDT_ADDRESS=
71
+ # Testnet contract addresses: when empty, the shared ecosystem defaults from
72
+ # @pasosdejesus/mpdj apply (Celo Sepolia SLEARN + MockUSDT).
73
+ NEXT_PUBLIC_SLEARN_TESTNET=
74
+ NEXT_PUBLIC_USDT_TESTNET=
72
75
  NEXT_PUBLIC_USDT_DECIMALS=6
73
76
 
74
77
  # -- Explorer URL --
@@ -1,14 +1,85 @@
1
1
  #!/bin/sh
2
+ #
3
+ # prepadJ.sh — OpenBSD/adJ Hardhat compatibility (pnpm workspace version)
4
+ #
5
+ # Compiles the @nomicfoundation/solidity-analyzer native addon for OpenBSD.
6
+ # Without it, `hardhat compile` fails because the platform has no prebuilt
7
+ # binary (Unsupported OS: openbsd).
8
+ #
9
+ # Prerequisites (once, as root):
10
+ # doas corepack enable
11
+ # and Rust/cargo available (the addon is built from source).
12
+ #
13
+ # Usage:
14
+ # cd apps/contracts
15
+ # sh bin/prepadJ.sh
16
+ #
17
+ set -e
2
18
 
3
- yarn install
4
- mkdir -p tmpart
5
- sed -e "s/freebsd/openbsd/g" node_modules/@nomicfoundation/solidity-analyzer/index.js > tmpart/index-sa.js
6
- cp tmpart/index-sa.js node_modules/@nomicfoundation/solidity-analyzer/index.js
7
- cd node_modules/@nomicfoundation/solidity-analyzer/
8
- doas corepack enable
9
- yarn
10
- yarn build
11
- cd ../../..
19
+ APP=$(cd "$(dirname "$0")/.." && pwd)
20
+ ROOT=$(cd "$APP/../.." && pwd)
21
+
22
+ echo "=== prepadJ: OpenBSD Hardhat compatibility (pnpm workspace) ==="
23
+
24
+ # The virtual store lives at the workspace root; older layouts kept it in the app.
25
+ SOLA_DIR=""
26
+ for STORE in "$ROOT/node_modules/.pnpm" "$APP/node_modules/.pnpm" "$APP/../node_modules/.pnpm"; do
27
+ [ -d "$STORE" ] || continue
28
+ FOUND=$(find "$STORE" -maxdepth 1 -name "@nomicfoundation+solidity-analyzer@*" -type d | head -1)
29
+ if [ -n "$FOUND" ]; then
30
+ SOLA_DIR="$FOUND"
31
+ break
32
+ fi
33
+ done
34
+ if [ -z "$SOLA_DIR" ]; then
35
+ echo "ERROR: solidity-analyzer not found. Run: pnpm install"
36
+ exit 1
37
+ fi
38
+ SOLA_SRC="$SOLA_DIR/node_modules/@nomicfoundation/solidity-analyzer"
39
+ echo "solidity-analyzer: $SOLA_SRC"
40
+
41
+ if [ -f "$SOLA_SRC/solidity-analyzer.openbsd-x64.node" ]; then
42
+ echo "Native addon already exists — skipping build"
43
+ exit 0
44
+ fi
45
+
46
+ sed -e 's/freebsd/openbsd/g' "$SOLA_SRC/index.js" > /tmp/sa-index.js
47
+ # Break the hard link first: writing over it would patch the shared pnpm store.
48
+ rm -f "$SOLA_SRC/index.js"
49
+ cp /tmp/sa-index.js "$SOLA_SRC/index.js"
50
+ echo "Patched index.js (freebsd → openbsd)"
51
+
52
+ TMPDIR=$(mktemp -d /tmp/sa-build.XXXXXX)
53
+ echo "Building in temp directory: $TMPDIR"
54
+ cp -r "$SOLA_SRC"/* "$TMPDIR"/
55
+ cp "$SOLA_SRC"/.yarnrc.yml "$TMPDIR"/ 2>/dev/null || true
56
+ cp "$SOLA_SRC"/.yarnrc "$TMPDIR"/ 2>/dev/null || true
57
+ cp "$SOLA_SRC"/Cargo.toml "$TMPDIR"/ 2>/dev/null || true
58
+ cp -r "$SOLA_SRC"/src "$TMPDIR"/ 2>/dev/null || true
59
+ cp -r "$SOLA_SRC"/build.rs "$TMPDIR"/ 2>/dev/null || true
60
+
61
+ cd "$TMPDIR"
62
+ echo "Installing dependencies (yarn)..."
12
63
  yarn
13
- cp tmpart/index-sa.js node_modules/@nomicfoundation/solidity-analyzer/index.js
64
+ echo "Building native addon..."
14
65
  yarn build
66
+
67
+ NODE_FILE=$(ls *.node 2>/dev/null | head -1)
68
+ if [ -z "$NODE_FILE" ]; then
69
+ NODE_FILE=$(find . -name "*.node" -type f | head -1)
70
+ fi
71
+ if [ -z "$NODE_FILE" ]; then
72
+ echo "ERROR: No .node file produced. Check build output."
73
+ exit 1
74
+ fi
75
+ NODE_FILE_ABS="$TMPDIR/$NODE_FILE"
76
+
77
+ cd "$APP"
78
+ cp "$NODE_FILE_ABS" "$SOLA_SRC/"
79
+ echo "Copied $NODE_FILE to $SOLA_SRC"
80
+
81
+ rm -rf "$TMPDIR"
82
+
83
+ echo "=== prepadJ: Verifying with pnpm build ==="
84
+ pnpm build
85
+ echo "=== prepadJ: Done ==="
@@ -11,7 +11,7 @@ packages:
11
11
  catalog:
12
12
  # ecosistema y motores
13
13
  '@pasosdejesus/m': ^{{m_version}}
14
- '@pasosdejesus/mpdj': ^0.2.15
14
+ '@pasosdejesus/mpdj': ^0.3.0
15
15
  '@pasosdejesus/usdt': ^0.1.3
16
16
  # compartidas por apps/web y apps/contracts
17
17
  typescript: 5.9.3
@@ -25,6 +25,12 @@ catalog:
25
25
  kysely-postgres-js: 3.0.0
26
26
  pg: 8.17.2
27
27
 
28
+ # pnpm 11 aplica `minimumReleaseAge` (24 h) y rechaza un lockfile con paquetes
29
+ # publicados hace menos de 24 h. Los paquetes del ecosistema se excluyen: se
30
+ # publican junto con `m` y conviene poder instalarlos de inmediato.
31
+ minimumReleaseAgeExclude:
32
+ - '@pasosdejesus/*'
33
+
28
34
  # Paquetes cuyo script de instalación se permite ejecutar (OpenBSD/adJ).
29
35
  allowBuilds:
30
36
  '@pasosdejesus/m': true
package/man/man1/m.1 ADDED
@@ -0,0 +1,212 @@
1
+ .\" $OpenBSD$
2
+ .Dd $Mdocdate: October 20 2026 $
3
+ .Dt M 1
4
+ .Os
5
+ .Sh NAME
6
+ .Nm m
7
+ .Nd CLI for Next.js and Hardhat projects
8
+ .Sh SYNOPSIS
9
+ .Nm
10
+ .Op Fl Vh
11
+ .Ar command
12
+ .Op Ar args ...
13
+ .Sh DESCRIPTION
14
+ The
15
+ .Nm
16
+ command scaffolds and manages integrated Next.js and Hardhat
17
+ applications: projects (m:create, m:update, m:check), databases,
18
+ engines, wallets, end-to-end tests and environment checks.
19
+ .Sh COMMANDS
20
+ .Ss AI
21
+ .Bl -tag -width Ds
22
+ .It Cm ai:context Op Ar flags
23
+ Genera contexto del proyecto para chat IA (compatible con DeepSeek)
24
+ .It Cm ai:edit Op Ar flags
25
+ Aplica cambios desde el portapapeles (formato diff de DeepSeek)
26
+ .It Cm ai:readfile Op Ar file
27
+ Muestra contenido de archivos (como read_file de Claude Code)
28
+ .It Cm ai:writefile Op Ar file
29
+ Crea o reemplaza un archivo con el contenido del portapapeles
30
+ .It Cm ai:grep Op Ar pattern
31
+ Busca texto en archivos (grep)
32
+ .It Cm ai:glob Op Ar pattern
33
+ Busca archivos por patrón (glob)
34
+ .El
35
+ .Ss ENV
36
+ .Bl -tag -width Ds
37
+ .It Cm env:diff Op Ar base [target]
38
+ Compara .env.example vs .env mostrando variables faltantes, sobrantes y
39
+ diferentes
40
+ .It Cm env:check Op Ar [file...]
41
+ Avisa de variables de entorno renombradas en el ecosistema (informativo)
42
+ .El
43
+ .Ss Project
44
+ .Bl -tag -width Ds
45
+ .It Cm m:create Ar name
46
+ Crea un nuevo proyecto
47
+ .It Cm m:update
48
+ Sincroniza el proyecto actual con las mejoras de las plantillas
49
+ (interactivo)
50
+ .It Cm m:check Op Ar --json|--strict|--fix
51
+ Verifica la estructura del proyecto (workspace, apps/web,
52
+ apps/contracts, catalog) y reporta hallazgos (--json, --strict, --fix)
53
+ .El
54
+ .Ss Help
55
+ .Bl -tag -width Ds
56
+ .It Cm m:man Op Ar --out <file>
57
+ Genera la página de manual en mdoc desde el registro de comandos (--out
58
+ <archivo>)
59
+ .El
60
+ .Ss Test
61
+ .Bl -tag -width Ds
62
+ .It Cm test:e2e:summary Op Ar output
63
+ Muestra el resultado por spec de uno o más logs de test:e2e y los
64
+ compara (marca las filas que difieren)
65
+ .It Cm warmup Op Ar output
66
+ Calienta un sitio (compila rutas en secuencial y verifica en paralelo)
67
+ leyendo e2e/warmup-paths.json o package.json:e2e.warmupPaths.
68
+ Opcional: filtro, --sequential
69
+ .El
70
+ .Ss Database
71
+ .Bl -tag -width Ds
72
+ .It Cm db:create
73
+ Crea la base de datos
74
+ .It Cm db:drop
75
+ Elimina la base de datos
76
+ .It Cm db:super:createuser
77
+ Crea un superusuario para la base de datos
78
+ .It Cm db:structure:dump
79
+ Vuelca la estructura de la base de datos
80
+ .It Cm db:structure:load
81
+ Carga la estructura de la base de datos
82
+ .It Cm db:migrate
83
+ Ejecuta las migraciones de la base de datos
84
+ .It Cm db:mig:make Ar name
85
+ Crea un nuevo archivo de migración
86
+ .It Cm db:rollback Op Ar --step N
87
+ Revierte la última migración (--step N para revertir N)
88
+ .It Cm db:seed
89
+ Siembra la base de datos
90
+ .It Cm db:console Op Ar query
91
+ Abre una consola de base de datos
92
+ .It Cm db:test
93
+ Prueba la conexión a la base de datos de forma no interactiva
94
+ .It Cm db:dump Op Ar name
95
+ Respaldar la base de datos (datos + esquema) en db/backups/
96
+ .It Cm db:restore Op Ar name
97
+ Restaurar la base de datos desde un respaldo en db/backups/
98
+ .El
99
+ .Ss Engine
100
+ .Bl -tag -width Ds
101
+ .It Cm eng:list
102
+ Lista motores disponibles
103
+ .It Cm eng:sync
104
+ Regenera el m-engine.generated.ts de un motor desde sus fuentes (--check
105
+ no escribe; --vendor lo copia)
106
+ .It Cm eng:remove
107
+ Quita una copia vendorizada de un motor de packages/generated (--drop
108
+ borra además sus tablas)
109
+ .It Cm eng:verify
110
+ Guarda el m-engine.generated.ts de un motor contra sus fuentes y su
111
+ intención
112
+ .It Cm eng:check
113
+ Verifica esquemas de motores
114
+ .It Cm eng:setup
115
+ Escribe en el consumidor las migraciones de los motores (db/migrations);
116
+ --check falla en CI si está atrasado
117
+ .It Cm eng:seed
118
+ Carga el seed de un motor (db/seed.sql.gz); msip conserva su seed
119
+ idempotente (--force recarga, --check reporta)
120
+ .It Cm eng:wba:setup
121
+ Crea archivos de migración WBA
122
+ .It Cm eng:credentials:setup
123
+ Crea archivos de migración credentials
124
+ .It Cm eng:msip:setup Op Ar flags
125
+ Escribe en el consumidor las migraciones del modelo msip que faltan
126
+ (db/migrations); --check falla en CI si está atrasado
127
+ .It Cm eng:msip:seed Op Ar flags
128
+ Carga los datos iniciales de msip (catálogos + geografía); --file
129
+ <sql> para el dataset completo, --force recarga, --check reporta
130
+ .It Cm eng:msip:baseline Op Ar flags
131
+ Imprime el baseline publicado del modelo msip (--out <archivo> para
132
+ guardarlo)
133
+ .It Cm eng:msip:dump Op Ar flags
134
+ Genera el baseline del modelo msip desde una base de referencia
135
+ .It Cm eng:msip:verify Op Ar flags
136
+ Verifica el baseline publicado de msip contra una estructura de
137
+ referencia (guard de derivación + D12)
138
+ .El
139
+ .Ss Engine/Opwallet
140
+ .Bl -tag -width Ds
141
+ .It Cm eng:opwallet:generate
142
+ Genera una nueva billetera con mnemotécnico
143
+ .It Cm eng:opwallet:approve
144
+ Aprueba gasto de token ERC20
145
+ .It Cm eng:opwallet:list
146
+ Lista billeteras almacenadas
147
+ .It Cm eng:opwallet:import
148
+ Importa una billetera desde mnemotécnico o clave privada
149
+ .It Cm eng:opwallet:send
150
+ Envía tokens nativos o ERC20
151
+ .It Cm eng:opwallet:balance
152
+ Consulta saldo de billetera
153
+ .It Cm eng:opwallet:sign
154
+ Firma una transacción offline (airgapped)
155
+ .It Cm eng:opwallet:broadcast
156
+ Transmite una transacción firmada
157
+ .It Cm eng:opwallet:call
158
+ Lee datos de un contrato inteligente
159
+ .It Cm eng:opwallet:derive
160
+ Deriva billetera hija desde mnemotécnico
161
+ .It Cm eng:opwallet:keccak
162
+ Calcula hash Keccak-256 de un texto
163
+ .El
164
+ .Ss Requirements
165
+ .Bl -tag -width Ds
166
+ .It Cm req:list
167
+ Lista requerimientos de REQ/ con estado y cross-project
168
+ .It Cm req:show Ar N
169
+ Muestra un requerimiento de REQ/
170
+ .It Cm req:cross
171
+ Lista requerimientos con impacto cross-project
172
+ .It Cm req:compare Op Ar N
173
+ Compara REQ local con issue remoto (GitLab/GitHub)
174
+ .It Cm req:sync-from-repo Ar N
175
+ Actualiza REQ local desde issue remoto
176
+ .It Cm req:sync-to-repo Ar N
177
+ Actualiza issue remoto desde REQ local
178
+ .It Cm req:list-repo
179
+ Lista issues abiertos del repositorio remoto
180
+ .It Cm req:create Ar title
181
+ Crea nuevo issue remoto y REQ local (repo asigna IID)
182
+ .It Cm req:close Ar N
183
+ Cierra un requerimiento: sync→repo, cierra issue, elimina local
184
+ .El
185
+ .Sh ENVIRONMENT
186
+ .Bl -tag -width Ds
187
+ .It Ev PGUSER , Ev PGPASSWORD , Ev PGDATABASE
188
+ PostgreSQL connection for the database commands and the test project.
189
+ .It Ev E2E_RETRIES
190
+ Default retry count for
191
+ .Cm test:e2e .
192
+ .It Ev E2E_LOG_DIR
193
+ Directory for the E2E logs (default
194
+ .Pa /tmp ) .
195
+ .It Ev E2E_SPEC_DELAY_MS
196
+ Delay between specs during an E2E run.
197
+ .El
198
+ .Sh FILES
199
+ .Bl -tag -width Ds
200
+ .It Pa .env
201
+ Project environment (consumers keep it in
202
+ .Pa apps/.env ) .
203
+ .It Pa ~/.m/wallets/
204
+ Encrypted operator wallets written by
205
+ .Cm eng:opwallet:* .
206
+ .It Pa m-extensions/
207
+ Project-specific hooks loaded by the CLI.
208
+ .El
209
+ .Sh EXIT STATUS
210
+ .Ex -std
211
+ .Sh SEE ALSO
212
+ .Xr sh 1