@pasosdejesus/m 0.16.1 → 0.17.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/dist/m.js +43 -0
- package/dist/plugin.d.ts +1 -0
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +2 -0
- package/dist/util/extensions.d.ts +15 -0
- package/dist/util/extensions.d.ts.map +1 -0
- package/dist/util/extensions.js +59 -0
- package/dist/util/hooks.d.ts +28 -0
- package/dist/util/hooks.d.ts.map +1 -0
- package/dist/util/hooks.js +53 -0
- package/package.json +1 -1
package/dist/m.js
CHANGED
|
@@ -28,6 +28,7 @@ import { cliTranslations } from './i18n/locales/cli.js';
|
|
|
28
28
|
import { problem, success } from './util/colors.js';
|
|
29
29
|
import { parseFlags } from './util/cli-parser.js';
|
|
30
30
|
import { getPluginCommands } from './plugin.js';
|
|
31
|
+
import { loadExtensions } from './util/extensions.js';
|
|
31
32
|
// Custom .env loading
|
|
32
33
|
const CWD = process.cwd();
|
|
33
34
|
const searchPaths = [
|
|
@@ -39,10 +40,52 @@ for (const p of searchPaths) {
|
|
|
39
40
|
if (fs.existsSync(p))
|
|
40
41
|
dotenv.config({ path: p, override: true, quiet: true });
|
|
41
42
|
}
|
|
43
|
+
/**
|
|
44
|
+
* Auto-discover plugins from package.json.
|
|
45
|
+
* Looks for dependencies matching @pasosdejesus/m-* pattern
|
|
46
|
+
* and imports them (each plugin self-registers via registerCommands).
|
|
47
|
+
*/
|
|
48
|
+
async function loadPlugins() {
|
|
49
|
+
const pkgPaths = [
|
|
50
|
+
path.join(CWD, 'package.json'),
|
|
51
|
+
path.join(CWD, '..', 'package.json'),
|
|
52
|
+
path.join(CWD, '..', '..', 'package.json'),
|
|
53
|
+
];
|
|
54
|
+
let pkg = null;
|
|
55
|
+
for (const p of pkgPaths) {
|
|
56
|
+
if (fs.existsSync(p)) {
|
|
57
|
+
try {
|
|
58
|
+
pkg = JSON.parse(fs.readFileSync(p, 'utf-8'));
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
catch { }
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (!pkg)
|
|
65
|
+
return;
|
|
66
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
67
|
+
for (const [name] of Object.entries(deps)) {
|
|
68
|
+
// Match @pasosdejesus/m-* plugins (e.g., @pasosdejesus/mpdj)
|
|
69
|
+
if (name.startsWith('@pasosdejesus/m') && name !== '@pasosdejesus/m') {
|
|
70
|
+
try {
|
|
71
|
+
await import(name);
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
// Plugin not installed or not a valid module — skip silently
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// Also support packages with mEngine: true metadata
|
|
78
|
+
// This requires resolving the package.json of the dependency
|
|
79
|
+
}
|
|
80
|
+
}
|
|
42
81
|
async function main() {
|
|
43
82
|
const locale = detectLocale();
|
|
44
83
|
setLocale(locale);
|
|
45
84
|
const cliT = createTranslator(locale, cliTranslations, commonCli);
|
|
85
|
+
// Auto-discover plugins from package.json
|
|
86
|
+
await loadPlugins();
|
|
87
|
+
// Load m-extensions/ (project-specific hooks)
|
|
88
|
+
await loadExtensions();
|
|
46
89
|
const commands = {
|
|
47
90
|
'db:create': { handler: runDbCreate, description: cliT('cmd.db_create_description') },
|
|
48
91
|
'db:drop': { handler: runDbDrop, description: cliT('cmd.db_drop_description') },
|
package/dist/plugin.d.ts
CHANGED
|
@@ -7,4 +7,5 @@ export interface CommandDef {
|
|
|
7
7
|
}
|
|
8
8
|
export declare function registerCommands(commands: Record<string, CommandDef>): void;
|
|
9
9
|
export declare function getPluginCommands(): Record<string, CommandDef>;
|
|
10
|
+
export { registerHook, runHooks } from './util/hooks.js';
|
|
10
11
|
//# sourceMappingURL=plugin.d.ts.map
|
package/dist/plugin.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,CAAC,GAAG,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAChD,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAID,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,GAAG,IAAI,CAE3E;AAED,wBAAgB,iBAAiB,IAAI,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAE9D"}
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,CAAC,GAAG,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAChD,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAID,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,GAAG,IAAI,CAE3E;AAED,wBAAgB,iBAAiB,IAAI,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAE9D;AAGD,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAA"}
|
package/dist/plugin.js
CHANGED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extension loader for m — auto-discovers and loads m-extensions/.
|
|
3
|
+
*
|
|
4
|
+
* Searches upward from process.cwd() for a directory named "m-extensions"
|
|
5
|
+
* and imports all .js and .ts files found within.
|
|
6
|
+
*
|
|
7
|
+
* "Y todo lo que hagáis, hacedlo de corazón, como para el Señor y no para los hombres" (Colosenses 3:23)
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Load all extension files from m-extensions/ directory.
|
|
11
|
+
* Each file is dynamically imported; its side effects (registerHook calls)
|
|
12
|
+
* register hooks that will fire at the appropriate extension points.
|
|
13
|
+
*/
|
|
14
|
+
export declare function loadExtensions(): Promise<void>;
|
|
15
|
+
//# sourceMappingURL=extensions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extensions.d.ts","sourceRoot":"","sources":["../../src/util/extensions.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAwBH;;;;GAIG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAoBpD"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extension loader for m — auto-discovers and loads m-extensions/.
|
|
3
|
+
*
|
|
4
|
+
* Searches upward from process.cwd() for a directory named "m-extensions"
|
|
5
|
+
* and imports all .js and .ts files found within.
|
|
6
|
+
*
|
|
7
|
+
* "Y todo lo que hagáis, hacedlo de corazón, como para el Señor y no para los hombres" (Colosenses 3:23)
|
|
8
|
+
*/
|
|
9
|
+
import { readdir, access as fsAccess } from 'node:fs/promises';
|
|
10
|
+
import { join, dirname } from 'node:path';
|
|
11
|
+
/**
|
|
12
|
+
* Find the nearest m-extensions/ directory by searching upward from cwd.
|
|
13
|
+
*/
|
|
14
|
+
async function findExtensionsDir() {
|
|
15
|
+
let dir = process.cwd();
|
|
16
|
+
for (let i = 0; i < 10; i++) {
|
|
17
|
+
const extDir = join(dir, 'm-extensions');
|
|
18
|
+
try {
|
|
19
|
+
await fsAccess(extDir);
|
|
20
|
+
return extDir;
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
const parent = dirname(dir);
|
|
24
|
+
if (parent === dir)
|
|
25
|
+
break;
|
|
26
|
+
dir = parent;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Load all extension files from m-extensions/ directory.
|
|
33
|
+
* Each file is dynamically imported; its side effects (registerHook calls)
|
|
34
|
+
* register hooks that will fire at the appropriate extension points.
|
|
35
|
+
*/
|
|
36
|
+
export async function loadExtensions() {
|
|
37
|
+
const extDir = await findExtensionsDir();
|
|
38
|
+
if (!extDir)
|
|
39
|
+
return;
|
|
40
|
+
let files;
|
|
41
|
+
try {
|
|
42
|
+
files = await readdir(extDir);
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
for (const file of files) {
|
|
48
|
+
if (!file.endsWith('.js') && !file.endsWith('.ts'))
|
|
49
|
+
continue;
|
|
50
|
+
if (file.endsWith('.d.ts'))
|
|
51
|
+
continue;
|
|
52
|
+
try {
|
|
53
|
+
await import(join(extDir, file));
|
|
54
|
+
}
|
|
55
|
+
catch (err) {
|
|
56
|
+
console.error(`[m] Failed to load extension ${file}: ${err.message || err}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook system for m extensions.
|
|
3
|
+
*
|
|
4
|
+
* Projects can register hooks to inject logic at specific extension points.
|
|
5
|
+
* Hooks are async callbacks that receive a context object.
|
|
6
|
+
*
|
|
7
|
+
* "Y todo lo que hagáis, hacedlo de corazón, como para el Señor y no para los hombres" (Colosenses 3:23)
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Register a hook callback for a named extension point.
|
|
11
|
+
* Safe to call multiple times — callbacks are appended.
|
|
12
|
+
*/
|
|
13
|
+
export declare function registerHook(name: string, callback: (ctx: any) => Promise<void>): void;
|
|
14
|
+
/**
|
|
15
|
+
* Run all registered hooks for a named extension point.
|
|
16
|
+
* Callbacks are executed in series (order of registration).
|
|
17
|
+
* Errors are caught and logged; they do not stop subsequent hooks.
|
|
18
|
+
*/
|
|
19
|
+
export declare function runHooks(name: string, ctx: any): Promise<void>;
|
|
20
|
+
/**
|
|
21
|
+
* Clear all registered hooks (for testing).
|
|
22
|
+
*/
|
|
23
|
+
export declare function clearHooks(): void;
|
|
24
|
+
/**
|
|
25
|
+
* Get hook names and callback counts (for debugging/testing).
|
|
26
|
+
*/
|
|
27
|
+
export declare function debugHooks(): Record<string, number>;
|
|
28
|
+
//# sourceMappingURL=hooks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/util/hooks.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAKtF;AAED;;;;GAIG;AACH,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAWpE;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,IAAI,CAEjC;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAMnD"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook system for m extensions.
|
|
3
|
+
*
|
|
4
|
+
* Projects can register hooks to inject logic at specific extension points.
|
|
5
|
+
* Hooks are async callbacks that receive a context object.
|
|
6
|
+
*
|
|
7
|
+
* "Y todo lo que hagáis, hacedlo de corazón, como para el Señor y no para los hombres" (Colosenses 3:23)
|
|
8
|
+
*/
|
|
9
|
+
const hooks = new Map();
|
|
10
|
+
/**
|
|
11
|
+
* Register a hook callback for a named extension point.
|
|
12
|
+
* Safe to call multiple times — callbacks are appended.
|
|
13
|
+
*/
|
|
14
|
+
export function registerHook(name, callback) {
|
|
15
|
+
if (!hooks.has(name)) {
|
|
16
|
+
hooks.set(name, []);
|
|
17
|
+
}
|
|
18
|
+
hooks.get(name).push(callback);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Run all registered hooks for a named extension point.
|
|
22
|
+
* Callbacks are executed in series (order of registration).
|
|
23
|
+
* Errors are caught and logged; they do not stop subsequent hooks.
|
|
24
|
+
*/
|
|
25
|
+
export async function runHooks(name, ctx) {
|
|
26
|
+
const callbacks = hooks.get(name);
|
|
27
|
+
if (!callbacks || callbacks.length === 0)
|
|
28
|
+
return;
|
|
29
|
+
for (const cb of callbacks) {
|
|
30
|
+
try {
|
|
31
|
+
await cb(ctx);
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
console.error(`[m] Hook "${name}" failed: ${err.message || err}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Clear all registered hooks (for testing).
|
|
40
|
+
*/
|
|
41
|
+
export function clearHooks() {
|
|
42
|
+
hooks.clear();
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Get hook names and callback counts (for debugging/testing).
|
|
46
|
+
*/
|
|
47
|
+
export function debugHooks() {
|
|
48
|
+
const out = {};
|
|
49
|
+
for (const [name, cbs] of hooks) {
|
|
50
|
+
out[name] = cbs.length;
|
|
51
|
+
}
|
|
52
|
+
return out;
|
|
53
|
+
}
|