oh-my-customcode 1.1.91 → 1.1.93

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/README.md CHANGED
@@ -249,7 +249,7 @@ oh-my-customcode ships 42 lifecycle hook scripts covering security, drift detect
249
249
 
250
250
  Most hooks are advisory (exit 0) — they warn but never block. A small number of hard-block hooks (e.g. `stage-blocker`, `rule-deletion-guard`) reject the tool call outright (exit 2). oh-my-customcode's own governance rules (`.claude/rules/`) follow an **advisory-first enforcement model**: prompt-based guidance is the default, and a rule is only promoted to a blocking hook after repeated, observed violations. Rules also retire — clauses tied to since-fixed platform bugs or that go unused for two minor releases are wrapped in HTML comments (still readable via the source file, invisible to the agent's context) rather than left to accumulate indefinitely.
251
251
 
252
- The hook source of truth is `.claude/hooks/hooks.json`; `omcustom init` compiles it into the `hooks` block of `.claude/settings.json` (via `src/core/hooks-settings.ts`), which is the file Claude Code actually loads.
252
+ The hook source of truth is `.claude/hooks/hooks.json`; `omcustom init` compiles it into the `hooks` block of `.claude/settings.json` (via `src/core/hooks-settings.ts`), which is the file Claude Code actually loads. Hook commands are anchored as `bash "${CLAUDE_PROJECT_DIR:-.}/.claude/hooks/<path>"`, so hooks keep working when the session's working directory moves to a subdirectory. Contributors: do not hand-edit the `hooks` blocks in settings; edit `hooks.json` and run `bun run sync:hooks` (also run at the end of `bun run build`) to regenerate them. Existing installs need no manual step: `omcustom update` (full or hooks component) and `omcustom init --backup` automatically migrate old relative hook commands in `.claude/settings.local.json`, and custom hooks are left untouched.
253
253
 
254
254
  ---
255
255
 
package/dist/cli/index.js CHANGED
@@ -217,7 +217,7 @@ var init_package = __esm(() => {
217
217
  workspaces: [
218
218
  "packages/*"
219
219
  ],
220
- version: "1.1.91",
220
+ version: "1.1.93",
221
221
  description: "Batteries-included agent harness for Claude Code",
222
222
  type: "module",
223
223
  bin: {
@@ -241,7 +241,8 @@ var init_package = __esm(() => {
241
241
  },
242
242
  scripts: {
243
243
  dev: "bun run src/cli/index.ts",
244
- build: "bun build src/cli/index.ts --outdir dist/cli --target node && bun build src/index.ts --outdir dist --target node && bun run scripts/sync-source-lockfile.ts",
244
+ build: "bun build src/cli/index.ts --outdir dist/cli --target node && bun build src/index.ts --outdir dist --target node && bun run scripts/sync-source-lockfile.ts && bun run scripts/sync-hooks-settings.ts",
245
+ "sync:hooks": "bun run scripts/sync-hooks-settings.ts",
245
246
  test: "bun test tests/ packages/eval-core/",
246
247
  "test:unit": "bun test tests/unit",
247
248
  "test:integration": "bun test tests/integration",
@@ -15615,6 +15616,8 @@ var MESSAGES = {
15615
15616
  "install.entry_md_skipped": "{{entry}} skipped ({{reason}})",
15616
15617
  "install.lockfile_generated": "Lockfile generated ({{files}} files tracked)",
15617
15618
  "install.lockfile_failed": "Failed to generate lockfile: {{error}}",
15619
+ "install.hook_commands_migrated": "Migrated {{rewritten}} hook command(s) in settings.local.json",
15620
+ "install.hook_commands_migration_failed": "Failed to migrate hook commands in settings.local.json: {{error}}",
15618
15621
  "lockfile.not_found": "Lockfile not found: {{path}}",
15619
15622
  "lockfile.invalid_version": "Invalid lockfile version: {{path}}",
15620
15623
  "lockfile.invalid_structure": "Invalid lockfile structure: {{path}}",
@@ -15636,6 +15639,8 @@ var MESSAGES = {
15636
15639
  "update.lockfile_failed": "Failed to regenerate lockfile: {{error}}",
15637
15640
  "update.protected_file_updated": "⟳ Protected file {{file}} in {{component}} updated: {{hint}}",
15638
15641
  "update.namespace_synced": "Namespace synced: {{file}} ({{component}})",
15642
+ "update.hook_commands_migrated": "Migrated {{count}} hook command(s) to CLAUDE_PROJECT_DIR-anchored paths",
15643
+ "update.hook_commands_migration_failed": "Failed to migrate hook commands in {{path}}",
15639
15644
  "config.load_failed": "Failed to load config: {{error}}",
15640
15645
  "config.not_found": "Config not found at {{path}}, using defaults",
15641
15646
  "config.saved": "Config saved to {{path}}",
@@ -15661,6 +15666,8 @@ var MESSAGES = {
15661
15666
  "install.entry_md_skipped": "{{entry}} 건너뜀 ({{reason}})",
15662
15667
  "install.lockfile_generated": "잠금 파일 생성 완료 ({{files}}개 파일 추적)",
15663
15668
  "install.lockfile_failed": "잠금 파일 생성 실패: {{error}}",
15669
+ "install.hook_commands_migrated": "settings.local.json의 훅 명령 {{rewritten}}개를 마이그레이션했습니다",
15670
+ "install.hook_commands_migration_failed": "settings.local.json의 훅 명령 마이그레이션에 실패했습니다: {{error}}",
15664
15671
  "lockfile.not_found": "잠금 파일 없음: {{path}}",
15665
15672
  "lockfile.invalid_version": "잠금 파일 버전 유효하지 않음: {{path}}",
15666
15673
  "lockfile.invalid_structure": "잠금 파일 구조 유효하지 않음: {{path}}",
@@ -15682,6 +15689,8 @@ var MESSAGES = {
15682
15689
  "update.lockfile_failed": "잠금 파일 재생성 실패: {{error}}",
15683
15690
  "update.protected_file_updated": "⟳ 보호 파일 {{file}} ({{component}}) 업데이트됨: {{hint}}",
15684
15691
  "update.namespace_synced": "네임스페이스 동기화: {{file}} ({{component}})",
15692
+ "update.hook_commands_migrated": "CLAUDE_PROJECT_DIR 기준 경로로 훅 명령 {{count}}개를 마이그레이션했습니다",
15693
+ "update.hook_commands_migration_failed": "{{path}}의 훅 명령 마이그레이션에 실패했습니다",
15685
15694
  "config.load_failed": "설정 로드 실패: {{error}}",
15686
15695
  "config.not_found": "{{path}}에 설정 없음, 기본값 사용",
15687
15696
  "config.saved": "설정 저장: {{path}}",
@@ -17349,6 +17358,52 @@ function getDefaultWorkflow() {
17349
17358
  };
17350
17359
  }
17351
17360
 
17361
+ // src/core/hook-command-migration.ts
17362
+ var OLD_HOOK_COMMAND = /^(bash )?(?:\.\/)?\.claude\/hooks\/((?:scripts\/)?[A-Za-z0-9._-]+\.sh)$/;
17363
+ function rewriteRelativeHookCommand(command) {
17364
+ const match = OLD_HOOK_COMMAND.exec(command);
17365
+ if (match === null) {
17366
+ return null;
17367
+ }
17368
+ const interpreter = match[1] ?? "";
17369
+ return `${interpreter}"\${CLAUDE_PROJECT_DIR:-.}/.claude/hooks/${match[2]}"`;
17370
+ }
17371
+ function isRecord(value) {
17372
+ return typeof value === "object" && value !== null && !Array.isArray(value);
17373
+ }
17374
+ function rewriteNode(node, counter) {
17375
+ if (Array.isArray(node)) {
17376
+ return node.map((item) => rewriteNode(item, counter));
17377
+ }
17378
+ if (!isRecord(node)) {
17379
+ return node;
17380
+ }
17381
+ const out = {};
17382
+ for (const [key, value] of Object.entries(node)) {
17383
+ if (key === "command" && typeof value === "string") {
17384
+ const rewritten = rewriteRelativeHookCommand(value);
17385
+ if (rewritten !== null) {
17386
+ counter.count++;
17387
+ out[key] = rewritten;
17388
+ continue;
17389
+ }
17390
+ }
17391
+ out[key] = rewriteNode(value, counter);
17392
+ }
17393
+ return out;
17394
+ }
17395
+ function migrateHookCommands(settings) {
17396
+ if (!isRecord(settings.hooks)) {
17397
+ return { settings, rewritten: 0 };
17398
+ }
17399
+ const counter = { count: 0 };
17400
+ const hooks = rewriteNode(settings.hooks, counter);
17401
+ if (counter.count === 0) {
17402
+ return { settings, rewritten: 0 };
17403
+ }
17404
+ return { settings: { ...settings, hooks }, rewritten: counter.count };
17405
+ }
17406
+
17352
17407
  // src/core/hooks-settings.ts
17353
17408
  init_fs();
17354
17409
  import { dirname as dirname3 } from "node:path";
@@ -18036,6 +18091,32 @@ async function installHooksSettings(targetDir, _options, result) {
18036
18091
  warn("install.hooks_settings_failed", { error: message });
18037
18092
  }
18038
18093
  }
18094
+ var BOM = "\uFEFF";
18095
+ async function migrateRestoredHookCommands(targetDir, result) {
18096
+ const layout = getProviderLayout();
18097
+ const settingsPath = join8(targetDir, layout.rootDir, "settings.local.json");
18098
+ if (!await fileExists(settingsPath)) {
18099
+ return;
18100
+ }
18101
+ try {
18102
+ const raw = await readTextFile(settingsPath);
18103
+ const hasBom = raw.startsWith(BOM);
18104
+ const trailingNewline = raw.endsWith(`
18105
+ `) ? `
18106
+ ` : "";
18107
+ const current = JSON.parse(hasBom ? raw.slice(BOM.length) : raw);
18108
+ const { settings, rewritten } = migrateHookCommands(current);
18109
+ if (rewritten > 0) {
18110
+ const body = `${JSON.stringify(settings, null, 2)}${trailingNewline}`;
18111
+ await writeTextFile(settingsPath, hasBom ? `${BOM}${body}` : body);
18112
+ debug("install.hook_commands_migrated", { rewritten: String(rewritten) });
18113
+ }
18114
+ } catch (err) {
18115
+ const message = err instanceof Error ? err.message : String(err);
18116
+ result.warnings.push(`Failed to migrate hook commands in settings.local.json: ${message}`);
18117
+ warn("install.hook_commands_migration_failed", { error: message });
18118
+ }
18119
+ }
18039
18120
  async function installEntryDocWithTracking(targetDir, options, result) {
18040
18121
  const language = options.language ?? DEFAULT_LANGUAGE2;
18041
18122
  const overwrite = !!(options.force || options.backup);
@@ -18111,6 +18192,7 @@ async function install(options) {
18111
18192
  result.warnings.push(`Failed to restore ${failure.path}: ${failure.reason}`);
18112
18193
  }
18113
18194
  }
18195
+ await migrateRestoredHookCommands(options.targetDir, result);
18114
18196
  await cleanupPreservation(preservation.tempDir);
18115
18197
  }
18116
18198
  await updateInstallConfig(options.targetDir, options, result.installedComponents);
@@ -20948,6 +21030,37 @@ async function backfillStatusLineRefreshInterval(targetDir, options) {
20948
21030
  });
20949
21031
  }
20950
21032
  }
21033
+ async function migrateHookCommandsInSettingsLocal(targetDir, options) {
21034
+ if (options.dryRun) {
21035
+ return;
21036
+ }
21037
+ const layout = getProviderLayout();
21038
+ const settingsPath = join18(targetDir, layout.rootDir, "settings.local.json");
21039
+ if (!await fileExists(settingsPath)) {
21040
+ return;
21041
+ }
21042
+ try {
21043
+ const raw = await readTextFile(settingsPath);
21044
+ const bom = raw.startsWith("\uFEFF") ? "\uFEFF" : "";
21045
+ const parsed = JSON.parse(bom ? raw.slice(bom.length) : raw);
21046
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
21047
+ return;
21048
+ }
21049
+ const { settings, rewritten } = migrateHookCommands(parsed);
21050
+ if (rewritten === 0) {
21051
+ return;
21052
+ }
21053
+ const trailingNewline = raw.endsWith(`
21054
+ `) ? `
21055
+ ` : "";
21056
+ await writeTextFile(settingsPath, `${bom}${JSON.stringify(settings, null, 2)}${trailingNewline}`);
21057
+ info("update.hook_commands_migrated", { count: String(rewritten) });
21058
+ } catch {
21059
+ warn("update.hook_commands_migration_failed", {
21060
+ path: settingsPath
21061
+ });
21062
+ }
21063
+ }
20951
21064
  async function runFullUpdatePostProcessing(options, result, config) {
20952
21065
  const isFullUpdate = !options.components || options.components.length === 0;
20953
21066
  if (isFullUpdate) {
@@ -20960,6 +21073,9 @@ async function runFullUpdatePostProcessing(options, result, config) {
20960
21073
  await backfillStatusLineRefreshInterval(options.targetDir, options);
20961
21074
  }
20962
21075
  }
21076
+ if (isFullUpdate || options.components?.includes("hooks")) {
21077
+ await migrateHookCommandsInSettingsLocal(options.targetDir, options);
21078
+ }
20963
21079
  if (!options.dryRun) {
20964
21080
  config.version = result.newVersion;
20965
21081
  config.lastUpdated = new Date().toISOString();
package/dist/index.js CHANGED
@@ -330,6 +330,8 @@ var MESSAGES = {
330
330
  "install.entry_md_skipped": "{{entry}} skipped ({{reason}})",
331
331
  "install.lockfile_generated": "Lockfile generated ({{files}} files tracked)",
332
332
  "install.lockfile_failed": "Failed to generate lockfile: {{error}}",
333
+ "install.hook_commands_migrated": "Migrated {{rewritten}} hook command(s) in settings.local.json",
334
+ "install.hook_commands_migration_failed": "Failed to migrate hook commands in settings.local.json: {{error}}",
333
335
  "lockfile.not_found": "Lockfile not found: {{path}}",
334
336
  "lockfile.invalid_version": "Invalid lockfile version: {{path}}",
335
337
  "lockfile.invalid_structure": "Invalid lockfile structure: {{path}}",
@@ -351,6 +353,8 @@ var MESSAGES = {
351
353
  "update.lockfile_failed": "Failed to regenerate lockfile: {{error}}",
352
354
  "update.protected_file_updated": "⟳ Protected file {{file}} in {{component}} updated: {{hint}}",
353
355
  "update.namespace_synced": "Namespace synced: {{file}} ({{component}})",
356
+ "update.hook_commands_migrated": "Migrated {{count}} hook command(s) to CLAUDE_PROJECT_DIR-anchored paths",
357
+ "update.hook_commands_migration_failed": "Failed to migrate hook commands in {{path}}",
354
358
  "config.load_failed": "Failed to load config: {{error}}",
355
359
  "config.not_found": "Config not found at {{path}}, using defaults",
356
360
  "config.saved": "Config saved to {{path}}",
@@ -376,6 +380,8 @@ var MESSAGES = {
376
380
  "install.entry_md_skipped": "{{entry}} 건너뜀 ({{reason}})",
377
381
  "install.lockfile_generated": "잠금 파일 생성 완료 ({{files}}개 파일 추적)",
378
382
  "install.lockfile_failed": "잠금 파일 생성 실패: {{error}}",
383
+ "install.hook_commands_migrated": "settings.local.json의 훅 명령 {{rewritten}}개를 마이그레이션했습니다",
384
+ "install.hook_commands_migration_failed": "settings.local.json의 훅 명령 마이그레이션에 실패했습니다: {{error}}",
379
385
  "lockfile.not_found": "잠금 파일 없음: {{path}}",
380
386
  "lockfile.invalid_version": "잠금 파일 버전 유효하지 않음: {{path}}",
381
387
  "lockfile.invalid_structure": "잠금 파일 구조 유효하지 않음: {{path}}",
@@ -397,6 +403,8 @@ var MESSAGES = {
397
403
  "update.lockfile_failed": "잠금 파일 재생성 실패: {{error}}",
398
404
  "update.protected_file_updated": "⟳ 보호 파일 {{file}} ({{component}}) 업데이트됨: {{hint}}",
399
405
  "update.namespace_synced": "네임스페이스 동기화: {{file}} ({{component}})",
406
+ "update.hook_commands_migrated": "CLAUDE_PROJECT_DIR 기준 경로로 훅 명령 {{count}}개를 마이그레이션했습니다",
407
+ "update.hook_commands_migration_failed": "{{path}}의 훅 명령 마이그레이션에 실패했습니다",
400
408
  "config.load_failed": "설정 로드 실패: {{error}}",
401
409
  "config.not_found": "{{path}}에 설정 없음, 기본값 사용",
402
410
  "config.saved": "설정 저장: {{path}}",
@@ -1094,6 +1102,52 @@ async function cleanupPreservation(tempDir) {
1094
1102
  }
1095
1103
  }
1096
1104
 
1105
+ // src/core/hook-command-migration.ts
1106
+ var OLD_HOOK_COMMAND = /^(bash )?(?:\.\/)?\.claude\/hooks\/((?:scripts\/)?[A-Za-z0-9._-]+\.sh)$/;
1107
+ function rewriteRelativeHookCommand(command) {
1108
+ const match = OLD_HOOK_COMMAND.exec(command);
1109
+ if (match === null) {
1110
+ return null;
1111
+ }
1112
+ const interpreter = match[1] ?? "";
1113
+ return `${interpreter}"\${CLAUDE_PROJECT_DIR:-.}/.claude/hooks/${match[2]}"`;
1114
+ }
1115
+ function isRecord(value) {
1116
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1117
+ }
1118
+ function rewriteNode(node, counter) {
1119
+ if (Array.isArray(node)) {
1120
+ return node.map((item) => rewriteNode(item, counter));
1121
+ }
1122
+ if (!isRecord(node)) {
1123
+ return node;
1124
+ }
1125
+ const out = {};
1126
+ for (const [key, value] of Object.entries(node)) {
1127
+ if (key === "command" && typeof value === "string") {
1128
+ const rewritten = rewriteRelativeHookCommand(value);
1129
+ if (rewritten !== null) {
1130
+ counter.count++;
1131
+ out[key] = rewritten;
1132
+ continue;
1133
+ }
1134
+ }
1135
+ out[key] = rewriteNode(value, counter);
1136
+ }
1137
+ return out;
1138
+ }
1139
+ function migrateHookCommands(settings) {
1140
+ if (!isRecord(settings.hooks)) {
1141
+ return { settings, rewritten: 0 };
1142
+ }
1143
+ const counter = { count: 0 };
1144
+ const hooks = rewriteNode(settings.hooks, counter);
1145
+ if (counter.count === 0) {
1146
+ return { settings, rewritten: 0 };
1147
+ }
1148
+ return { settings: { ...settings, hooks }, rewritten: counter.count };
1149
+ }
1150
+
1097
1151
  // src/core/hooks-settings.ts
1098
1152
  init_fs();
1099
1153
  import { dirname as dirname2 } from "node:path";
@@ -2026,6 +2080,32 @@ async function installHooksSettings(targetDir, _options, result) {
2026
2080
  warn("install.hooks_settings_failed", { error: message });
2027
2081
  }
2028
2082
  }
2083
+ var BOM = "\uFEFF";
2084
+ async function migrateRestoredHookCommands(targetDir, result) {
2085
+ const layout = getProviderLayout();
2086
+ const settingsPath = join5(targetDir, layout.rootDir, "settings.local.json");
2087
+ if (!await fileExists(settingsPath)) {
2088
+ return;
2089
+ }
2090
+ try {
2091
+ const raw = await readTextFile(settingsPath);
2092
+ const hasBom = raw.startsWith(BOM);
2093
+ const trailingNewline = raw.endsWith(`
2094
+ `) ? `
2095
+ ` : "";
2096
+ const current = JSON.parse(hasBom ? raw.slice(BOM.length) : raw);
2097
+ const { settings, rewritten } = migrateHookCommands(current);
2098
+ if (rewritten > 0) {
2099
+ const body = `${JSON.stringify(settings, null, 2)}${trailingNewline}`;
2100
+ await writeTextFile(settingsPath, hasBom ? `${BOM}${body}` : body);
2101
+ debug("install.hook_commands_migrated", { rewritten: String(rewritten) });
2102
+ }
2103
+ } catch (err) {
2104
+ const message = err instanceof Error ? err.message : String(err);
2105
+ result.warnings.push(`Failed to migrate hook commands in settings.local.json: ${message}`);
2106
+ warn("install.hook_commands_migration_failed", { error: message });
2107
+ }
2108
+ }
2029
2109
  async function installEntryDocWithTracking(targetDir, options, result) {
2030
2110
  const language = options.language ?? DEFAULT_LANGUAGE;
2031
2111
  const overwrite = !!(options.force || options.backup);
@@ -2101,6 +2181,7 @@ async function install(options) {
2101
2181
  result.warnings.push(`Failed to restore ${failure.path}: ${failure.reason}`);
2102
2182
  }
2103
2183
  }
2184
+ await migrateRestoredHookCommands(options.targetDir, result);
2104
2185
  await cleanupPreservation(preservation.tempDir);
2105
2186
  }
2106
2187
  await updateInstallConfig(options.targetDir, options, result.installedComponents);
@@ -2326,7 +2407,7 @@ var package_default = {
2326
2407
  workspaces: [
2327
2408
  "packages/*"
2328
2409
  ],
2329
- version: "1.1.91",
2410
+ version: "1.1.93",
2330
2411
  description: "Batteries-included agent harness for Claude Code",
2331
2412
  type: "module",
2332
2413
  bin: {
@@ -2350,7 +2431,8 @@ var package_default = {
2350
2431
  },
2351
2432
  scripts: {
2352
2433
  dev: "bun run src/cli/index.ts",
2353
- build: "bun build src/cli/index.ts --outdir dist/cli --target node && bun build src/index.ts --outdir dist --target node && bun run scripts/sync-source-lockfile.ts",
2434
+ build: "bun build src/cli/index.ts --outdir dist/cli --target node && bun build src/index.ts --outdir dist --target node && bun run scripts/sync-source-lockfile.ts && bun run scripts/sync-hooks-settings.ts",
2435
+ "sync:hooks": "bun run scripts/sync-hooks-settings.ts",
2354
2436
  test: "bun test tests/ packages/eval-core/",
2355
2437
  "test:unit": "bun test tests/unit",
2356
2438
  "test:integration": "bun test tests/integration",
@@ -5157,6 +5239,37 @@ async function backfillStatusLineRefreshInterval(targetDir, options) {
5157
5239
  });
5158
5240
  }
5159
5241
  }
5242
+ async function migrateHookCommandsInSettingsLocal(targetDir, options) {
5243
+ if (options.dryRun) {
5244
+ return;
5245
+ }
5246
+ const layout = getProviderLayout();
5247
+ const settingsPath = join7(targetDir, layout.rootDir, "settings.local.json");
5248
+ if (!await fileExists(settingsPath)) {
5249
+ return;
5250
+ }
5251
+ try {
5252
+ const raw = await readTextFile(settingsPath);
5253
+ const bom = raw.startsWith("\uFEFF") ? "\uFEFF" : "";
5254
+ const parsed = JSON.parse(bom ? raw.slice(bom.length) : raw);
5255
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
5256
+ return;
5257
+ }
5258
+ const { settings, rewritten } = migrateHookCommands(parsed);
5259
+ if (rewritten === 0) {
5260
+ return;
5261
+ }
5262
+ const trailingNewline = raw.endsWith(`
5263
+ `) ? `
5264
+ ` : "";
5265
+ await writeTextFile(settingsPath, `${bom}${JSON.stringify(settings, null, 2)}${trailingNewline}`);
5266
+ info("update.hook_commands_migrated", { count: String(rewritten) });
5267
+ } catch {
5268
+ warn("update.hook_commands_migration_failed", {
5269
+ path: settingsPath
5270
+ });
5271
+ }
5272
+ }
5160
5273
  async function runFullUpdatePostProcessing(options, result, config) {
5161
5274
  const isFullUpdate = !options.components || options.components.length === 0;
5162
5275
  if (isFullUpdate) {
@@ -5169,6 +5282,9 @@ async function runFullUpdatePostProcessing(options, result, config) {
5169
5282
  await backfillStatusLineRefreshInterval(options.targetDir, options);
5170
5283
  }
5171
5284
  }
5285
+ if (isFullUpdate || options.components?.includes("hooks")) {
5286
+ await migrateHookCommandsInSettingsLocal(options.targetDir, options);
5287
+ }
5172
5288
  if (!options.dryRun) {
5173
5289
  config.version = result.newVersion;
5174
5290
  config.lastUpdated = new Date().toISOString();
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "workspaces": [
4
4
  "packages/*"
5
5
  ],
6
- "version": "1.1.91",
6
+ "version": "1.1.93",
7
7
  "description": "Batteries-included agent harness for Claude Code",
8
8
  "type": "module",
9
9
  "bin": {
@@ -27,7 +27,8 @@
27
27
  },
28
28
  "scripts": {
29
29
  "dev": "bun run src/cli/index.ts",
30
- "build": "bun build src/cli/index.ts --outdir dist/cli --target node && bun build src/index.ts --outdir dist --target node && bun run scripts/sync-source-lockfile.ts",
30
+ "build": "bun build src/cli/index.ts --outdir dist/cli --target node && bun build src/index.ts --outdir dist --target node && bun run scripts/sync-source-lockfile.ts && bun run scripts/sync-hooks-settings.ts",
31
+ "sync:hooks": "bun run scripts/sync-hooks-settings.ts",
31
32
  "test": "bun test tests/ packages/eval-core/",
32
33
  "test:unit": "bun test tests/unit",
33
34
  "test:integration": "bun test tests/integration",