@eventmodelers/cli 1.0.49 → 1.0.51
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/cli.js +121 -18
- package/package.json +1 -1
- package/stacks/node/templates/build-kit/CLAUDE.md +1 -1
- package/stacks/node/templates/build-kit/lib/check-commit-scope.cjs +1 -1
- package/stacks/node/templates/root/package.json +1 -1
- package/stacks/supabase/templates/build-kit/CLAUDE.md +1 -1
- package/stacks/supabase/templates/build-kit/lib/check-commit-scope.cjs +1 -1
- package/stacks/supabase/templates/root/package.json +1 -1
package/cli.js
CHANGED
|
@@ -918,24 +918,7 @@ async function installStack(stackKey, stackCfg, options = {}) {
|
|
|
918
918
|
if (options.hooks) {
|
|
919
919
|
const hooksSrc = join(rootSrc, '.githooks');
|
|
920
920
|
if (existsSync(hooksSrc)) {
|
|
921
|
-
|
|
922
|
-
const preCommitHook = join(targetDir, '.githooks', 'pre-commit');
|
|
923
|
-
if (existsSync(preCommitHook)) {
|
|
924
|
-
// cpSync doesn't reliably carry over the executable bit across platforms,
|
|
925
|
-
// and git silently skips a non-executable hook.
|
|
926
|
-
try { execSync(`chmod +x "${preCommitHook}"`); } catch {}
|
|
927
|
-
}
|
|
928
|
-
try {
|
|
929
|
-
execSync('git rev-parse --git-dir', { cwd: targetDir, stdio: 'ignore' });
|
|
930
|
-
// core.hooksPath is resolved against the repo's actual top level, not `cwd` —
|
|
931
|
-
// a relative `.githooks` breaks silently (no error, hooks just don't run) when
|
|
932
|
-
// targetDir is a subfolder of a larger repo rather than the repo root itself.
|
|
933
|
-
// Use an absolute path so it's correct regardless of where the git root is.
|
|
934
|
-
execSync(`git config core.hooksPath "${join(targetDir, '.githooks')}"`, { cwd: targetDir });
|
|
935
|
-
console.log(' ✓ Installed .githooks/ and set core.hooksPath — commits touching src/slices/ are now scope-guarded');
|
|
936
|
-
} catch {
|
|
937
|
-
console.log(` ✓ Installed .githooks/ — run \`git config core.hooksPath ${join(targetDir, '.githooks')}\` once this directory is a git repo to activate it`);
|
|
938
|
-
}
|
|
921
|
+
configureHooks({ hooksSrc, targetDir });
|
|
939
922
|
} else {
|
|
940
923
|
console.log(' ℹ️ --hooks was given but this stack ships no .githooks/ template — nothing to install');
|
|
941
924
|
}
|
|
@@ -1192,6 +1175,33 @@ async function configureMcp(options = {}) {
|
|
|
1192
1175
|
}
|
|
1193
1176
|
}
|
|
1194
1177
|
|
|
1178
|
+
// Installs/refreshes the slice commit-scope guard (.githooks/pre-commit, running
|
|
1179
|
+
// .build-kit/lib/check-commit-scope.cjs) and wires it up via `git config
|
|
1180
|
+
// core.hooksPath .githooks`. Shared by `init --hooks`, `re-init --hooks`, and the
|
|
1181
|
+
// standalone `init-hooks` command so all three copy/chmod/git-config identically
|
|
1182
|
+
// instead of drifting apart — callers are responsible for checking `hooksSrc`
|
|
1183
|
+
// exists first, since what "no template for this stack" means differs per caller.
|
|
1184
|
+
function configureHooks({ hooksSrc, targetDir }) {
|
|
1185
|
+
copyDirContents(hooksSrc, join(targetDir, '.githooks'));
|
|
1186
|
+
const preCommitHook = join(targetDir, '.githooks', 'pre-commit');
|
|
1187
|
+
if (existsSync(preCommitHook)) {
|
|
1188
|
+
// cpSync doesn't reliably carry over the executable bit across platforms,
|
|
1189
|
+
// and git silently skips a non-executable hook.
|
|
1190
|
+
try { execSync(`chmod +x "${preCommitHook}"`); } catch {}
|
|
1191
|
+
}
|
|
1192
|
+
try {
|
|
1193
|
+
execSync('git rev-parse --git-dir', { cwd: targetDir, stdio: 'ignore' });
|
|
1194
|
+
// core.hooksPath is resolved against the repo's actual top level, not `cwd` —
|
|
1195
|
+
// a relative `.githooks` breaks silently (no error, hooks just don't run) when
|
|
1196
|
+
// targetDir is a subfolder of a larger repo rather than the repo root itself.
|
|
1197
|
+
// Use an absolute path so it's correct regardless of where the git root is.
|
|
1198
|
+
execSync(`git config core.hooksPath "${join(targetDir, '.githooks')}"`, { cwd: targetDir });
|
|
1199
|
+
console.log(' ✓ Installed .githooks/ and set core.hooksPath — commits touching src/slices/ are now scope-guarded');
|
|
1200
|
+
} catch {
|
|
1201
|
+
console.log(` ✓ Installed .githooks/ — run \`git config core.hooksPath ${join(targetDir, '.githooks')}\` once this directory is a git repo to activate it`);
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1204
|
+
|
|
1195
1205
|
// Registers the eventmodelers MCP server in `.mcp.json` at the project root, the
|
|
1196
1206
|
// same file/shape the `connect` skill's Step 3.5 produces — kept here as a
|
|
1197
1207
|
// belt-and-suspenders guarantee, since an agent executing that skill can skip a
|
|
@@ -1777,6 +1787,99 @@ program
|
|
|
1777
1787
|
await configureAgentHosts({ hosts, global: opts.global });
|
|
1778
1788
|
});
|
|
1779
1789
|
|
|
1790
|
+
program
|
|
1791
|
+
.command('init-hooks')
|
|
1792
|
+
.description('Install/refresh the slice commit-scope guard (.githooks/pre-commit) and set `git config core.hooksPath .githooks` — same as `init --hooks`/`re-init --hooks`, for installing the latest hooks or re-pointing git config at them without a full re-scaffold')
|
|
1793
|
+
.option('--stack <name>', `Which stack's .githooks/ template to install (${Object.keys(STACKS).join(', ')}) — defaults to whichever stack is recorded in install-manifest.json`)
|
|
1794
|
+
.action(async (opts) => {
|
|
1795
|
+
const targetDir = process.cwd();
|
|
1796
|
+
|
|
1797
|
+
let stackKey = opts.stack;
|
|
1798
|
+
if (stackKey && !STACKS[stackKey]) {
|
|
1799
|
+
console.error(`❌ Unknown stack "${stackKey}". Available: ${Object.keys(STACKS).join(', ')}`);
|
|
1800
|
+
process.exit(1);
|
|
1801
|
+
}
|
|
1802
|
+
if (!stackKey) {
|
|
1803
|
+
for (const name of KIT_DIR_NAMES) {
|
|
1804
|
+
const manifest = readJsonSafe(join(targetDir, name, '.eventmodelers', 'install-manifest.json'));
|
|
1805
|
+
if (manifest.stack && STACKS[manifest.stack]) {
|
|
1806
|
+
stackKey = manifest.stack;
|
|
1807
|
+
break;
|
|
1808
|
+
}
|
|
1809
|
+
}
|
|
1810
|
+
}
|
|
1811
|
+
if (!stackKey) {
|
|
1812
|
+
console.error(`❌ Can't tell which stack's .githooks/ template to install — pass --stack <name> (${Object.keys(STACKS).join(', ')}), or run \`init\`/\`re-init\` for one of those stacks first.`);
|
|
1813
|
+
process.exit(1);
|
|
1814
|
+
}
|
|
1815
|
+
|
|
1816
|
+
const hooksSrc = join(__dirname, 'stacks', stackKey, 'templates', 'root', '.githooks');
|
|
1817
|
+
if (!existsSync(hooksSrc)) {
|
|
1818
|
+
console.error(`❌ "${stackKey}" ships no .githooks/ template — nothing to install.`);
|
|
1819
|
+
process.exit(1);
|
|
1820
|
+
}
|
|
1821
|
+
|
|
1822
|
+
console.log('🪝 Configuring git hooks...');
|
|
1823
|
+
configureHooks({ hooksSrc, targetDir });
|
|
1824
|
+
});
|
|
1825
|
+
|
|
1826
|
+
program
|
|
1827
|
+
.command('disable-hooks')
|
|
1828
|
+
.description('Turn off the slice commit-scope guard by unsetting `git config core.hooksPath` — leaves .githooks/ on disk untouched; run `init-hooks` again any time to re-enable')
|
|
1829
|
+
.action(() => {
|
|
1830
|
+
const targetDir = process.cwd();
|
|
1831
|
+
|
|
1832
|
+
try {
|
|
1833
|
+
execSync('git rev-parse --git-dir', { cwd: targetDir, stdio: 'ignore' });
|
|
1834
|
+
} catch {
|
|
1835
|
+
console.error(`❌ ${targetDir} is not a git repository — nothing to unset.`);
|
|
1836
|
+
process.exit(1);
|
|
1837
|
+
}
|
|
1838
|
+
|
|
1839
|
+
let currentHooksPath = null;
|
|
1840
|
+
try {
|
|
1841
|
+
currentHooksPath = execSync('git config --get core.hooksPath', { cwd: targetDir, stdio: ['ignore', 'pipe', 'ignore'] }).toString().trim();
|
|
1842
|
+
} catch {
|
|
1843
|
+
// core.hooksPath isn't set — nothing to do
|
|
1844
|
+
}
|
|
1845
|
+
|
|
1846
|
+
if (!currentHooksPath) {
|
|
1847
|
+
console.log(' ℹ️ core.hooksPath is not set — the guard is already off, nothing to do.');
|
|
1848
|
+
return;
|
|
1849
|
+
}
|
|
1850
|
+
|
|
1851
|
+
execSync('git config --unset core.hooksPath', { cwd: targetDir });
|
|
1852
|
+
console.log(` ✓ Unset core.hooksPath (was "${currentHooksPath}") — the commit-scope guard is now off. Run \`init-hooks\` again to turn it back on.`);
|
|
1853
|
+
});
|
|
1854
|
+
|
|
1855
|
+
program
|
|
1856
|
+
.command('run-checks')
|
|
1857
|
+
.alias('run:checks')
|
|
1858
|
+
.description("Run this project's commit-scope checks (.build-kit/lib/check-commit-scope.cjs, the same runner .githooks/pre-commit calls) against the currently staged changeset. Works for any build-kit stack — stacks/installs that ship no checks yet report that and exit 0, so this is safe to call unconditionally (e.g. from an agent loop) without checking the stack first.")
|
|
1859
|
+
.action(() => {
|
|
1860
|
+
const cwd = process.cwd();
|
|
1861
|
+
// Mirrors `run`'s buildKitDir resolution: modeling-kit/bridge-kit installs share
|
|
1862
|
+
// KIT_DIR_NAMES but never ship check-commit-scope.cjs, so prefer whichever
|
|
1863
|
+
// installed dir isn't one of those over blindly taking the first match.
|
|
1864
|
+
const installedKitDirs = findAllInstalledKitDirs(cwd);
|
|
1865
|
+
const modelingKitDir = installedKitDirs.find((d) => d.endsWith(MODELING_KIT.kitDirName)) ?? null;
|
|
1866
|
+
const bridgeKitDir = installedKitDirs.find((d) => d.endsWith(BRIDGE_KIT.kitDirName)) ?? null;
|
|
1867
|
+
const kitDir = installedKitDirs.find((d) => d !== modelingKitDir && d !== bridgeKitDir) ?? installedKitDirs[0];
|
|
1868
|
+
|
|
1869
|
+
const checkScript = join(kitDir, 'lib', 'check-commit-scope.cjs');
|
|
1870
|
+
if (!existsSync(checkScript)) {
|
|
1871
|
+
console.log(`ℹ️ ${relative(cwd, kitDir)} ships no checks yet — nothing to run.`);
|
|
1872
|
+
return;
|
|
1873
|
+
}
|
|
1874
|
+
|
|
1875
|
+
console.log(`🔎 Running checks from ${relative(cwd, checkScript)}...`);
|
|
1876
|
+
try {
|
|
1877
|
+
execSync(`node "${checkScript}"`, { cwd: kitDir, stdio: 'inherit' });
|
|
1878
|
+
} catch (err) {
|
|
1879
|
+
process.exit(err.status || 1);
|
|
1880
|
+
}
|
|
1881
|
+
});
|
|
1882
|
+
|
|
1780
1883
|
credentialFlags(program
|
|
1781
1884
|
.command('init-config')
|
|
1782
1885
|
.description('Configure credentials only — writes .eventmodelers/config.json in the current directory, or ~/.eventmodelers/config.json with --global')
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eventmodelers/cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.51",
|
|
4
4
|
"description": "Eventmodelers CLI — real-time Claude agent + skills for Claude Code, for any stack (Node, Supabase, Axon, Cratis, OpenCQRS, UmaDB, Kurrent, or modeling-only)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -75,7 +75,7 @@ It loads every check under `.build-kit/lib/checks/` and rejects the commit if an
|
|
|
75
75
|
- **tsc-build** — `npx tsc --noEmit` must still pass
|
|
76
76
|
|
|
77
77
|
If a commit is rejected, split it — commit the out-of-scope file separately from the slice work, or add
|
|
78
|
-
the missing test/fix the field — rather than passing `--no-verify`. Run `npm run
|
|
78
|
+
the missing test/fix the field — rather than passing `--no-verify`. Run `npm run run:checks` any time
|
|
79
79
|
you want to check staged files before committing. To add a new check, read
|
|
80
80
|
`.build-kit/lib/checks/README.md` and drop in a file following its interface — no other wiring needed.
|
|
81
81
|
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
// SLICE_PATTERN RegExp matching a path inside a slice's own folder
|
|
24
24
|
//
|
|
25
25
|
// Zero dependencies — plain Node, so it works from git's pre-commit hook
|
|
26
|
-
// (see ../../.githooks/pre-commit), from `npm run
|
|
26
|
+
// (see ../../.githooks/pre-commit), from `npm run run:checks`, or from CI.
|
|
27
27
|
// Invoked as: node .build-kit/lib/check-commit-scope.cjs
|
|
28
28
|
|
|
29
29
|
const { execSync } = require('child_process');
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"build": "tsc",
|
|
9
9
|
"start": "NODE_ENV=production node --env-file=.env --require ts-node/register server.ts",
|
|
10
10
|
"test": "tsx --test 'src/**/*.test.ts'",
|
|
11
|
-
"
|
|
11
|
+
"run:checks": "node .build-kit/lib/check-commit-scope.cjs"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
14
|
"@event-driven-io/emmett": "^0.42.1-alpha.1",
|
|
@@ -79,7 +79,7 @@ and rejects the commit if any of them find a problem:
|
|
|
79
79
|
- **tsc-build** — `npx tsc --noEmit` must still pass
|
|
80
80
|
|
|
81
81
|
If a commit is rejected, split it — commit the out-of-scope file separately from the slice work, or add
|
|
82
|
-
the missing test/fix the field — rather than passing `--no-verify`. Run `npm run
|
|
82
|
+
the missing test/fix the field — rather than passing `--no-verify`. Run `npm run run:checks` any time
|
|
83
83
|
you want to check staged files before committing. To add a new check, read
|
|
84
84
|
`.build-kit/lib/checks/README.md` and drop in a file following its interface — no other wiring needed.
|
|
85
85
|
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
// SLICE_PATTERN RegExp matching a path inside a slice's own folder
|
|
24
24
|
//
|
|
25
25
|
// Zero dependencies — plain Node, so it works from git's pre-commit hook
|
|
26
|
-
// (see ../../.githooks/pre-commit), from `npm run
|
|
26
|
+
// (see ../../.githooks/pre-commit), from `npm run run:checks`, or from CI.
|
|
27
27
|
// Invoked as: node .build-kit/lib/check-commit-scope.cjs
|
|
28
28
|
|
|
29
29
|
const { execSync } = require('child_process');
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"build": "tsc",
|
|
9
9
|
"start": "NODE_ENV=production node --env-file=.env --require ts-node/register server.ts",
|
|
10
10
|
"test": "tsx --test 'src/**/*.test.ts'",
|
|
11
|
-
"
|
|
11
|
+
"run:checks": "node .build-kit/lib/check-commit-scope.cjs"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
14
|
"@event-driven-io/emmett": "^0.42.1-alpha.1",
|