@eventmodelers/cli 1.0.48 → 1.0.50

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 CHANGED
@@ -918,20 +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
- copyDirContents(hooksSrc, join(targetDir, '.githooks'));
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
- execSync('git config core.hooksPath .githooks', { cwd: targetDir });
931
- console.log(' ✓ Installed .githooks/ and set core.hooksPath — commits touching src/slices/ are now scope-guarded');
932
- } catch {
933
- console.log(' ✓ Installed .githooks/ — run `git config core.hooksPath .githooks` once this directory is a git repo to activate it');
934
- }
921
+ configureHooks({ hooksSrc, targetDir });
935
922
  } else {
936
923
  console.log(' ℹ️ --hooks was given but this stack ships no .githooks/ template — nothing to install');
937
924
  }
@@ -1188,6 +1175,33 @@ async function configureMcp(options = {}) {
1188
1175
  }
1189
1176
  }
1190
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
+
1191
1205
  // Registers the eventmodelers MCP server in `.mcp.json` at the project root, the
1192
1206
  // same file/shape the `connect` skill's Step 3.5 produces — kept here as a
1193
1207
  // belt-and-suspenders guarantee, since an agent executing that skill can skip a
@@ -1773,6 +1787,71 @@ program
1773
1787
  await configureAgentHosts({ hosts, global: opts.global });
1774
1788
  });
1775
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
+
1776
1855
  credentialFlags(program
1777
1856
  .command('init-config')
1778
1857
  .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.48",
3
+ "version": "1.0.50",
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 check:scope` any time
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 check:scope`, or from CI.
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
- "check:scope": "node .build-kit/lib/check-commit-scope.cjs"
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",
@@ -54,6 +54,9 @@ echo ".env created successfully."
54
54
 
55
55
  if [ -f .githooks/pre-commit ] && git rev-parse --git-dir >/dev/null 2>&1; then
56
56
  chmod +x .githooks/pre-commit 2>/dev/null || true
57
- git config core.hooksPath .githooks
57
+ # core.hooksPath resolves against the repo's actual top level, not this directory —
58
+ # a relative ".githooks" silently breaks (no error, hooks just don't run) when this
59
+ # project sits in a subfolder of a larger repo instead of being the repo root itself.
60
+ git config core.hooksPath "$(pwd)/.githooks"
58
61
  echo "Configured git to use .githooks/ (slice commit-scope guard)."
59
62
  fi
@@ -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 check:scope` any time
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 check:scope`, or from CI.
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
- "check:scope": "node .build-kit/lib/check-commit-scope.cjs"
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",
@@ -54,6 +54,9 @@ echo ".env created successfully."
54
54
 
55
55
  if [ -f .githooks/pre-commit ] && git rev-parse --git-dir >/dev/null 2>&1; then
56
56
  chmod +x .githooks/pre-commit 2>/dev/null || true
57
- git config core.hooksPath .githooks
57
+ # core.hooksPath resolves against the repo's actual top level, not this directory —
58
+ # a relative ".githooks" silently breaks (no error, hooks just don't run) when this
59
+ # project sits in a subfolder of a larger repo instead of being the repo root itself.
60
+ git config core.hooksPath "$(pwd)/.githooks"
58
61
  echo "Configured git to use .githooks/ (slice commit-scope guard)."
59
62
  fi