delimit-cli 3.14.16 → 3.14.18

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.
@@ -322,14 +322,14 @@ function installClaudeHooks(tool, hookConfig) {
322
322
  if (!existingSecurity) {
323
323
  config.hooks.PreToolUse.push({
324
324
  matcher: 'Bash',
325
- if: "command matches 'npm publish' or command matches 'npx deploy' or command matches 'deploy' or command matches 'release'",
325
+ if: "command matches 'npm publish' or command matches 'npx deploy' or command matches 'deploy' or command matches 'release' or command matches 'docker compose up' or command matches 'docker-compose up' or command matches 'docker build'",
326
326
  hooks: [{
327
327
  type: 'command',
328
- command: `${npxCmd} security-audit`,
328
+ command: `${npxCmd} hook deploy-gate`,
329
329
  timeout: 30,
330
330
  }],
331
331
  });
332
- changes.push('PreToolUse:deploy-audit');
332
+ changes.push('PreToolUse:deploy-gate');
333
333
  }
334
334
  }
335
335
  }
@@ -696,14 +696,21 @@ async function hookSessionStart() {
696
696
  lines.push('[Delimit] No policy file found -- run "delimit init" to set up governance');
697
697
  }
698
698
 
699
- // Check for updates
699
+ // Auto-update check + install
700
700
  try {
701
701
  const pkgPath = path.join(__dirname, '..', 'package.json');
702
702
  const currentVersion = JSON.parse(fs.readFileSync(pkgPath, 'utf-8')).version;
703
703
  const { execSync: execS } = require('child_process');
704
704
  const latest = execS('npm view delimit-cli version 2>/dev/null', { encoding: 'utf-8', timeout: 5000 }).trim();
705
705
  if (latest && latest !== currentVersion && latest > currentVersion) {
706
- lines.push(`[Delimit] Update available: ${currentVersion} ${latest} (run: npx delimit-cli@latest setup)`);
706
+ lines.push(`[Delimit] Updating ${currentVersion} -> ${latest}...`);
707
+ try {
708
+ execS('npm install -g delimit-cli@latest 2>/dev/null', { timeout: 30000, stdio: 'pipe' });
709
+ execS('delimit-cli setup --yes 2>/dev/null', { timeout: 30000, stdio: 'pipe' });
710
+ lines.push(`[Delimit] Updated to ${latest}`);
711
+ } catch {
712
+ lines.push(`[Delimit] Auto-update failed. Run: npm install -g delimit-cli@latest`);
713
+ }
707
714
  }
708
715
  } catch { /* offline or timeout — skip silently */ }
709
716
 
@@ -937,6 +944,97 @@ async function hookPreCommit() {
937
944
 
938
945
  // ---------------------------------------------------------------------------
939
946
  // Exports
947
+ // ---------------------------------------------------------------------------
948
+ // Deploy gate hook — runs smoke test before any deploy (LED-024 feedback)
949
+ // ---------------------------------------------------------------------------
950
+
951
+ async function hookDeployGate() {
952
+ const lines = [];
953
+ lines.push('[Delimit] Deploy gate check');
954
+ lines.push('');
955
+
956
+ let blocked = false;
957
+
958
+ // 1. Check for common import/syntax errors
959
+ const cwd = process.cwd();
960
+ const hasDockerCompose = fs.existsSync(path.join(cwd, 'docker-compose.yml'))
961
+ || fs.existsSync(path.join(cwd, 'docker-compose.yaml'))
962
+ || fs.existsSync(path.join(cwd, 'compose.yml'));
963
+
964
+ // 2. Check for Python import errors if it's a Python project
965
+ const hasPython = fs.existsSync(path.join(cwd, 'requirements.txt'))
966
+ || fs.existsSync(path.join(cwd, 'pyproject.toml'))
967
+ || fs.existsSync(path.join(cwd, 'setup.py'));
968
+
969
+ if (hasPython) {
970
+ try {
971
+ // Find the main app module
972
+ const appDirs = ['app', 'src', 'api'];
973
+ for (const dir of appDirs) {
974
+ const initFile = path.join(cwd, dir, '__init__.py');
975
+ const mainFile = path.join(cwd, dir, 'main.py');
976
+ if (fs.existsSync(initFile) || fs.existsSync(mainFile)) {
977
+ try {
978
+ execSync(`python3 -c "import ${dir}" 2>&1`, {
979
+ encoding: 'utf-8',
980
+ timeout: 10000,
981
+ cwd,
982
+ });
983
+ lines.push(`[Delimit] ✓ ${dir}/ imports clean`);
984
+ } catch (e) {
985
+ lines.push(`[Delimit] ✗ ${dir}/ import error: ${e.stdout || e.stderr || e.message}`);
986
+ blocked = true;
987
+ }
988
+ }
989
+ }
990
+ } catch { /* ignore */ }
991
+ }
992
+
993
+ // 3. Check for Node.js syntax errors
994
+ const hasNode = fs.existsSync(path.join(cwd, 'package.json'));
995
+ if (hasNode) {
996
+ try {
997
+ execSync('node -e "require(\'./\')" 2>&1', {
998
+ encoding: 'utf-8',
999
+ timeout: 5000,
1000
+ cwd,
1001
+ });
1002
+ lines.push('[Delimit] ✓ Node.js entry point loads');
1003
+ } catch {
1004
+ // Not all projects have a main entry — skip silently
1005
+ }
1006
+ }
1007
+
1008
+ // 4. Check for uncommitted changes
1009
+ try {
1010
+ const status = execSync('git status --porcelain 2>/dev/null', {
1011
+ encoding: 'utf-8',
1012
+ timeout: 3000,
1013
+ cwd,
1014
+ }).trim();
1015
+ if (status) {
1016
+ const fileCount = status.split('\n').length;
1017
+ lines.push(`[Delimit] ⚠ ${fileCount} uncommitted file(s) — consider committing before deploy`);
1018
+ }
1019
+ } catch { /* not a git repo */ }
1020
+
1021
+ // 5. Result
1022
+ lines.push('');
1023
+ if (blocked) {
1024
+ lines.push('[Delimit] ✗ DEPLOY BLOCKED — fix import errors above');
1025
+ lines.push('[Delimit] Run: delimit_test_smoke for full diagnostics');
1026
+ } else {
1027
+ lines.push('[Delimit] ✓ Deploy gate passed');
1028
+ }
1029
+ lines.push('');
1030
+
1031
+ process.stdout.write(lines.join('\n') + '\n');
1032
+
1033
+ if (blocked) {
1034
+ process.exit(1);
1035
+ }
1036
+ }
1037
+
940
1038
  // ---------------------------------------------------------------------------
941
1039
 
942
1040
  module.exports = {
@@ -954,6 +1052,7 @@ module.exports = {
954
1052
  hookSessionStart,
955
1053
  hookPreTool,
956
1054
  hookPreCommit,
1055
+ hookDeployGate,
957
1056
  countPendingStrategyItems,
958
1057
  getTopStrategyItem,
959
1058
  findClaudeHookGroup,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "delimit-cli",
3
3
  "mcpName": "io.github.delimit-ai/delimit-mcp-server",
4
- "version": "3.14.16",
4
+ "version": "3.14.18",
5
5
  "description": "Unify Claude Code, Codex, Cursor, and Gemini CLI with persistent context, governance, and multi-model debate.",
6
6
  "main": "index.js",
7
7
  "files": [