@massu/core 2.5.1 → 2.5.2

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.
@@ -4,6 +4,12 @@ var __defProp = Object.defineProperty;
4
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
8
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
9
+ }) : x)(function(x) {
10
+ if (typeof require !== "undefined") return require.apply(this, arguments);
11
+ throw Error('Dynamic require of "' + x + '" is not supported');
12
+ });
7
13
  var __esm = (fn, res, err) => function __init() {
8
14
  if (err) throw err[0];
9
15
  try {
@@ -697,6 +703,13 @@ var init_config = __esm({
697
703
  });
698
704
  LanguageFrameworkEntrySchema = z2.object({
699
705
  framework: z2.string().optional(),
706
+ // `source_dirs` is emitted by `init` (commands/init.ts:417) and existence-checked
707
+ // by config validation (init.ts:868-876), but until 2026-08-14 it survived only via
708
+ // `.passthrough()` — declared in the file, untyped in the schema. `lib/source-layout.ts`
709
+ // derives the index builders' candidate set from it, so it is typed here rather than
710
+ // read as an unknown: a consumer that has to shape-check its own SoT is one branch away
711
+ // from silently contributing `undefined` to a path predicate.
712
+ source_dirs: z2.array(z2.string()).optional(),
700
713
  test_framework: z2.string().optional(),
701
714
  test: z2.string().optional(),
702
715
  runtime: z2.string().optional(),
@@ -1814,8 +1827,8 @@ function resolveModelDir() {
1814
1827
  function resolveWasmDir() {
1815
1828
  try {
1816
1829
  const req3 = createRequire3(import.meta.url);
1817
- const main2 = req3.resolve(ORT_PKG);
1818
- return dirname6(main2);
1830
+ const main3 = req3.resolve(ORT_PKG);
1831
+ return dirname6(main3);
1819
1832
  } catch {
1820
1833
  return null;
1821
1834
  }
@@ -3988,9 +4001,16 @@ var init_memory_db = __esm({
3988
4001
  // src/hooks/classify-failure.ts
3989
4002
  init_config();
3990
4003
  init_memory_db();
3991
- import { existsSync as existsSync9, readFileSync as readFileSync6, readdirSync as readdirSync2, unlinkSync as unlinkSync2, writeFileSync as writeFileSync3 } from "fs";
4004
+ import { existsSync as existsSync10, readFileSync as readFileSync7, readdirSync as readdirSync2, unlinkSync as unlinkSync2, writeFileSync as writeFileSync3 } from "fs";
4005
+ import { tmpdir as tmpdir3 } from "os";
4006
+ import { join as join7, basename as basename3 } from "path";
4007
+
4008
+ // src/hooks/fix-detector.ts
4009
+ init_config();
4010
+ import { execFileSync } from "child_process";
4011
+ import { existsSync as existsSync9, appendFileSync as appendFileSync3, mkdirSync as mkdirSync7, readFileSync as readFileSync6 } from "fs";
3992
4012
  import { tmpdir as tmpdir2 } from "os";
3993
- import { join as join6, basename as basename3 } from "path";
4013
+ import { join as join6 } from "path";
3994
4014
 
3995
4015
  // src/hooks/lib/write-hook-message.ts
3996
4016
  var HOOK_EVENTS = [
@@ -4027,9 +4047,237 @@ function writeHookContext(hookEventName, message) {
4027
4047
  );
4028
4048
  }
4029
4049
 
4030
- // src/hooks/classify-failure.ts
4050
+ // src/hooks/fix-detector.ts
4031
4051
  init_hook_failure_signal();
4052
+
4053
+ // src/hooks/lib/is-direct-invocation.ts
4054
+ import { pathToFileURL } from "url";
4055
+ function isDirectInvocation(moduleUrl) {
4056
+ const entry = process.argv[1];
4057
+ if (!entry) return false;
4058
+ try {
4059
+ return moduleUrl === pathToFileURL(entry).href;
4060
+ } catch {
4061
+ return false;
4062
+ }
4063
+ }
4064
+
4065
+ // src/hooks/fix-detector.ts
4032
4066
  var HOOK_EVENT = "PostToolUse";
4067
+ var TEST_OR_FIXTURE_PATH_PATTERNS = [
4068
+ /(^|\/)(__tests__|__fixtures__|tests?|fixtures?|spec)\//,
4069
+ /\.(test|spec)\.[cm]?[jt]sx?$/,
4070
+ /(^|\/)(test_[^/]+|[^/]+_test)\.py$/
4071
+ ];
4072
+ function isTestOrFixturePath(filePath) {
4073
+ return TEST_OR_FIXTURE_PATH_PATTERNS.some((re) => re.test(filePath));
4074
+ }
4075
+ var FIX_HEURISTICS = [
4076
+ {
4077
+ name: "removed_broken_code",
4078
+ test: (diff) => /^-.*\b(bug|broken|wrong|incorrect|typo|crash|error|fail|miss|stale)\b/m.test(diff)
4079
+ },
4080
+ {
4081
+ name: "added_error_handling",
4082
+ test: (diff) => {
4083
+ const added = (diff.match(/^\+.*(try|except|catch|guard|if.*nil|if.*None|validate|assert|raise|throw)/gm) || []).length;
4084
+ return added > 2;
4085
+ }
4086
+ },
4087
+ {
4088
+ name: "method_name_correction",
4089
+ test: (diff) => {
4090
+ const removed = diff.match(/^-.*\.([a-z_]+)\(/m);
4091
+ const added = diff.match(/^\+.*\.([a-z_]+)\(/m);
4092
+ return !!(removed && added && removed[1] !== added[1]);
4093
+ }
4094
+ },
4095
+ {
4096
+ name: "auth_fix",
4097
+ test: (diff) => /^\+.*(token|auth|header|X-Service|Bearer|credential)/im.test(diff)
4098
+ },
4099
+ {
4100
+ name: "nil_handling_fix",
4101
+ test: (diff) => /^\+.*(= nil|= None|\.isNil|is None|!= nil|is not None|guard let|if let|optional)/m.test(diff) && /^-/m.test(diff)
4102
+ },
4103
+ {
4104
+ name: "concurrency_fix",
4105
+ test: (diff) => /^\+.*(timeout|semaphore|lock|mutex|throttle|rate.limit|max_conn)/im.test(diff)
4106
+ },
4107
+ {
4108
+ name: "async_pattern_fix",
4109
+ test: (diff) => /^\+.*(@MainActor|async with|asyncio\.timeout|\.await)/.test(diff) && /^-/m.test(diff)
4110
+ },
4111
+ {
4112
+ name: "added_missing_import",
4113
+ test: (diff) => /^\+.*(import|from.*import|require)/.test(diff) && !/^-.*(import|from.*import|require)/m.test(diff)
4114
+ }
4115
+ ];
4116
+ function getSessionFlagPath(sessionId) {
4117
+ const dir = join6(tmpdir2(), "massu-auto-learning");
4118
+ if (!existsSync9(dir)) {
4119
+ mkdirSync7(dir, { recursive: true });
4120
+ }
4121
+ return join6(dir, `fixes-${sessionId.slice(0, 12)}.jsonl`);
4122
+ }
4123
+ function _stateDir() {
4124
+ const dir = join6(tmpdir2(), "massu-fix-detector-state");
4125
+ if (!existsSync9(dir)) {
4126
+ mkdirSync7(dir, { recursive: true });
4127
+ }
4128
+ return dir;
4129
+ }
4130
+ function _cwdHash(cwd) {
4131
+ let h = 5381;
4132
+ for (let i = 0; i < cwd.length; i++) {
4133
+ h = (h << 5) + h + cwd.charCodeAt(i) | 0;
4134
+ }
4135
+ return Math.abs(h).toString(36);
4136
+ }
4137
+ function isGitWorkTreeFast(cwd) {
4138
+ try {
4139
+ const cachePath = join6(_stateDir(), `worktree-${_cwdHash(cwd)}.json`);
4140
+ if (existsSync9(cachePath)) {
4141
+ const cached = JSON.parse(readFileSync6(cachePath, "utf-8"));
4142
+ const ageMs = Date.now() - cached.ts;
4143
+ if (ageMs < 36e5) return cached.isWorkTree;
4144
+ }
4145
+ let isWorkTree = false;
4146
+ try {
4147
+ execFileSync("git", ["rev-parse", "--is-inside-work-tree"], { cwd, timeout: 500, encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"] });
4148
+ isWorkTree = true;
4149
+ } catch {
4150
+ isWorkTree = false;
4151
+ }
4152
+ try {
4153
+ appendFileSync3(cachePath, "");
4154
+ const fs = __require("fs");
4155
+ fs.writeFileSync(cachePath, JSON.stringify({ isWorkTree, ts: Date.now() }));
4156
+ } catch {
4157
+ }
4158
+ return isWorkTree;
4159
+ } catch {
4160
+ return false;
4161
+ }
4162
+ }
4163
+ function _disabledFlagPath(sessionId) {
4164
+ return join6(_stateDir(), `disabled-${sessionId.slice(0, 12)}.flag`);
4165
+ }
4166
+ function isSessionAutoDisabled(sessionId) {
4167
+ try {
4168
+ return existsSync9(_disabledFlagPath(sessionId));
4169
+ } catch {
4170
+ return false;
4171
+ }
4172
+ }
4173
+ function markSessionAutoDisabled(sessionId, elapsedMs) {
4174
+ try {
4175
+ const fs = __require("fs");
4176
+ fs.writeFileSync(_disabledFlagPath(sessionId), `disabled: previous git diff took ${elapsedMs}ms
4177
+ `);
4178
+ } catch {
4179
+ }
4180
+ }
4181
+ async function main() {
4182
+ try {
4183
+ const input = await readStdin();
4184
+ const hookInput = JSON.parse(input);
4185
+ const filePath = hookInput.tool_input?.file_path;
4186
+ if (!filePath || !existsSync9(filePath)) {
4187
+ process.exit(0);
4188
+ return;
4189
+ }
4190
+ if (!/\.(py|swift|ts|tsx|js|jsx|rs|go|rb|sh)$/.test(filePath)) {
4191
+ process.exit(0);
4192
+ return;
4193
+ }
4194
+ const config = getConfig();
4195
+ const incidentDir = config.autoLearning?.incidentDir ?? "docs/incidents";
4196
+ const memoryDir = config.autoLearning?.memoryDir ?? "memory";
4197
+ if (filePath.includes(incidentDir) || filePath.includes(memoryDir) || filePath.includes("MEMORY.md")) {
4198
+ process.exit(0);
4199
+ return;
4200
+ }
4201
+ if (isTestOrFixturePath(filePath)) {
4202
+ process.exit(0);
4203
+ return;
4204
+ }
4205
+ if (config.autoLearning?.enabled === false || config.autoLearning?.fixDetection?.enabled === false) {
4206
+ process.exit(0);
4207
+ return;
4208
+ }
4209
+ const root = getProjectRoot();
4210
+ if (!isGitWorkTreeFast(root) || isSessionAutoDisabled(hookInput.session_id)) {
4211
+ process.exit(0);
4212
+ return;
4213
+ }
4214
+ let diff = "";
4215
+ try {
4216
+ const startMs = Date.now();
4217
+ diff = execFileSync("git", ["diff", "--", filePath], { cwd: root, timeout: 3e3, encoding: "utf-8" });
4218
+ if (!diff) {
4219
+ diff = execFileSync("git", ["diff", "HEAD", "--", filePath], { cwd: root, timeout: 3e3, encoding: "utf-8" });
4220
+ }
4221
+ const elapsedMs = Date.now() - startMs;
4222
+ if (elapsedMs > 2e3) {
4223
+ markSessionAutoDisabled(hookInput.session_id, elapsedMs);
4224
+ }
4225
+ } catch {
4226
+ process.exit(0);
4227
+ return;
4228
+ }
4229
+ if (!diff) {
4230
+ process.exit(0);
4231
+ return;
4232
+ }
4233
+ const enabledSignals = new Set(config.autoLearning?.fixDetection?.signals ?? FIX_HEURISTICS.map((h) => h.name));
4234
+ const detected = [];
4235
+ for (const heuristic of FIX_HEURISTICS) {
4236
+ if (enabledSignals.has(heuristic.name) && heuristic.test(diff)) {
4237
+ detected.push(heuristic.name);
4238
+ }
4239
+ }
4240
+ if (detected.length === 0) {
4241
+ process.exit(0);
4242
+ return;
4243
+ }
4244
+ const signal = {
4245
+ file: filePath,
4246
+ signals: detected,
4247
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
4248
+ };
4249
+ const flagPath = getSessionFlagPath(hookInput.session_id);
4250
+ appendFileSync3(flagPath, JSON.stringify(signal) + "\n");
4251
+ const lines = readFileSync6(flagPath, "utf-8").split("\n").filter(Boolean);
4252
+ if (lines.length === 1) {
4253
+ writeHookContext(
4254
+ HOOK_EVENT,
4255
+ `[Massu Auto-Learning] Bug fix detected in ${filePath} (signals: ${detected.join(", ")}). The auto-learning pipeline will prompt you at session end to create an incident report, derive a prevention rule, and add enforcement.`
4256
+ );
4257
+ }
4258
+ } catch (err) {
4259
+ recordHookFailure("fix-detector", err);
4260
+ }
4261
+ process.exit(0);
4262
+ }
4263
+ function readStdin() {
4264
+ return new Promise((resolve5) => {
4265
+ let data = "";
4266
+ process.stdin.setEncoding("utf-8");
4267
+ process.stdin.on("data", (chunk) => {
4268
+ data += chunk;
4269
+ });
4270
+ process.stdin.on("end", () => resolve5(data));
4271
+ setTimeout(() => resolve5(data), 3e3);
4272
+ });
4273
+ }
4274
+ if (isDirectInvocation(import.meta.url)) {
4275
+ main();
4276
+ }
4277
+
4278
+ // src/hooks/classify-failure.ts
4279
+ init_hook_failure_signal();
4280
+ var HOOK_EVENT2 = "PostToolUse";
4033
4281
  var BUG_FIX_INDICATORS = [
4034
4282
  /\b(catch|error|throw|fail|fix|bug|broken|missing|crash|wrong|typo|incorrect)\b/i
4035
4283
  ];
@@ -4037,7 +4285,7 @@ var CODE_EXTENSIONS = /\.(ts|tsx|js|jsx|py|swift|rs|go|rb|sh)$/;
4037
4285
  function getDedupeMarkerPath(sessionId, filePath) {
4038
4286
  const day = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
4039
4287
  const hash = simpleHash(filePath);
4040
- return join6(tmpdir2(), `massu-classify-${day}-${sessionId.slice(0, 8)}-${hash}`);
4288
+ return join7(tmpdir3(), `massu-classify-${day}-${sessionId.slice(0, 8)}-${hash}`);
4041
4289
  }
4042
4290
  function simpleHash(str) {
4043
4291
  let h = 0;
@@ -4047,13 +4295,13 @@ function simpleHash(str) {
4047
4295
  return Math.abs(h).toString(36);
4048
4296
  }
4049
4297
  function readFailureContextFiles() {
4050
- const dir = tmpdir2();
4298
+ const dir = tmpdir3();
4051
4299
  let context = "";
4052
4300
  try {
4053
4301
  const files = readdirSync2(dir).filter((f) => f.startsWith("massu-failure-context-"));
4054
4302
  for (const file of files) {
4055
4303
  try {
4056
- context += " " + readFileSync6(join6(dir, file), "utf-8");
4304
+ context += " " + readFileSync7(join7(dir, file), "utf-8");
4057
4305
  } catch {
4058
4306
  }
4059
4307
  }
@@ -4062,21 +4310,21 @@ function readFailureContextFiles() {
4062
4310
  return context.trim();
4063
4311
  }
4064
4312
  function cleanupFailureContextFiles() {
4065
- const dir = tmpdir2();
4313
+ const dir = tmpdir3();
4066
4314
  try {
4067
4315
  const files = readdirSync2(dir).filter((f) => f.startsWith("massu-failure-context-"));
4068
4316
  for (const file of files) {
4069
4317
  try {
4070
- unlinkSync2(join6(dir, file));
4318
+ unlinkSync2(join7(dir, file));
4071
4319
  } catch {
4072
4320
  }
4073
4321
  }
4074
4322
  } catch {
4075
4323
  }
4076
4324
  }
4077
- async function main() {
4325
+ async function main2() {
4078
4326
  try {
4079
- const input = await readStdin();
4327
+ const input = await readStdin2();
4080
4328
  const hookInput = JSON.parse(input);
4081
4329
  const filePath = hookInput.tool_input?.file_path;
4082
4330
  if (!filePath) {
@@ -4100,6 +4348,10 @@ async function main() {
4100
4348
  process.exit(0);
4101
4349
  return;
4102
4350
  }
4351
+ if (isTestOrFixturePath(relPath) || isTestOrFixturePath(filePath)) {
4352
+ process.exit(0);
4353
+ return;
4354
+ }
4103
4355
  const oldString = hookInput.tool_input?.old_string ?? "";
4104
4356
  const newString = hookInput.tool_input?.new_string ?? "";
4105
4357
  const content = hookInput.tool_input?.content ?? "";
@@ -4129,7 +4381,7 @@ async function main() {
4129
4381
  return;
4130
4382
  }
4131
4383
  const dedupeMarker = getDedupeMarkerPath(hookInput.session_id, filePath);
4132
- if (existsSync9(dedupeMarker)) {
4384
+ if (existsSync10(dedupeMarker)) {
4133
4385
  process.exit(0);
4134
4386
  return;
4135
4387
  }
@@ -4171,7 +4423,7 @@ function outputKnownPattern(match) {
4171
4423
  lines.push(` Covered by: ${match.rules.join(", ")}`);
4172
4424
  }
4173
4425
  lines.push(" No new rules needed. Reference existing incident if logging.");
4174
- writeHookContext(HOOK_EVENT, lines.join("\n"));
4426
+ writeHookContext(HOOK_EVENT2, lines.join("\n"));
4175
4427
  }
4176
4428
  function outputSimilarPattern(match) {
4177
4429
  const lines = [];
@@ -4181,7 +4433,7 @@ function outputSimilarPattern(match) {
4181
4433
  lines.push(` Check if existing rules cover this case: ${match.rules.join(", ")}`);
4182
4434
  }
4183
4435
  lines.push(" If genuinely new: create incident + prevention rule + enforcement.");
4184
- writeHookContext(HOOK_EVENT, lines.join("\n"));
4436
+ writeHookContext(HOOK_EVENT2, lines.join("\n"));
4185
4437
  }
4186
4438
  function outputNewPattern(fileName, match) {
4187
4439
  const lines = [];
@@ -4195,9 +4447,9 @@ function outputNewPattern(fileName, match) {
4195
4447
  lines.push(" 1. INCIDENT REPORT");
4196
4448
  lines.push(" 2. PREVENTION RULE (if new failure pattern)");
4197
4449
  lines.push(" 3. ENFORCEMENT (hook or static check)");
4198
- writeHookContext(HOOK_EVENT, lines.join("\n"));
4450
+ writeHookContext(HOOK_EVENT2, lines.join("\n"));
4199
4451
  }
4200
- function readStdin() {
4452
+ function readStdin2() {
4201
4453
  return new Promise((resolve5) => {
4202
4454
  let data = "";
4203
4455
  process.stdin.setEncoding("utf-8");
@@ -4208,4 +4460,6 @@ function readStdin() {
4208
4460
  setTimeout(() => resolve5(data), 3e3);
4209
4461
  });
4210
4462
  }
4211
- main();
4463
+ if (isDirectInvocation(import.meta.url)) {
4464
+ main2();
4465
+ }
@@ -1167,6 +1167,13 @@ var init_config = __esm({
1167
1167
  });
1168
1168
  LanguageFrameworkEntrySchema = z2.object({
1169
1169
  framework: z2.string().optional(),
1170
+ // `source_dirs` is emitted by `init` (commands/init.ts:417) and existence-checked
1171
+ // by config validation (init.ts:868-876), but until 2026-08-14 it survived only via
1172
+ // `.passthrough()` — declared in the file, untyped in the schema. `lib/source-layout.ts`
1173
+ // derives the index builders' candidate set from it, so it is typed here rather than
1174
+ // read as an unknown: a consumer that has to shape-check its own SoT is one branch away
1175
+ // from silently contributing `undefined` to a path predicate.
1176
+ source_dirs: z2.array(z2.string()).optional(),
1170
1177
  test_framework: z2.string().optional(),
1171
1178
  test: z2.string().optional(),
1172
1179
  runtime: z2.string().optional(),
@@ -4086,6 +4093,20 @@ function toolResponseText(raw) {
4086
4093
  // src/hooks/cost-tracker.ts
4087
4094
  init_hook_failure_signal();
4088
4095
  init_timestamps();
4096
+
4097
+ // src/hooks/lib/is-direct-invocation.ts
4098
+ import { pathToFileURL } from "url";
4099
+ function isDirectInvocation(moduleUrl) {
4100
+ const entry = process.argv[1];
4101
+ if (!entry) return false;
4102
+ try {
4103
+ return moduleUrl === pathToFileURL(entry).href;
4104
+ } catch {
4105
+ return false;
4106
+ }
4107
+ }
4108
+
4109
+ // src/hooks/cost-tracker.ts
4089
4110
  var CHARS_PER_TOKEN = 4;
4090
4111
  function estimateTokens(text) {
4091
4112
  return Math.ceil(text.length / CHARS_PER_TOKEN);
@@ -4123,4 +4144,6 @@ function readStdin() {
4123
4144
  setTimeout(() => resolve5(data), 3e3);
4124
4145
  });
4125
4146
  }
4126
- main();
4147
+ if (isDirectInvocation(import.meta.url)) {
4148
+ main();
4149
+ }
@@ -703,6 +703,13 @@ var init_config = __esm({
703
703
  });
704
704
  LanguageFrameworkEntrySchema = z2.object({
705
705
  framework: z2.string().optional(),
706
+ // `source_dirs` is emitted by `init` (commands/init.ts:417) and existence-checked
707
+ // by config validation (init.ts:868-876), but until 2026-08-14 it survived only via
708
+ // `.passthrough()` — declared in the file, untyped in the schema. `lib/source-layout.ts`
709
+ // derives the index builders' candidate set from it, so it is typed here rather than
710
+ // read as an unknown: a consumer that has to shape-check its own SoT is one branch away
711
+ // from silently contributing `undefined` to a path predicate.
712
+ source_dirs: z2.array(z2.string()).optional(),
706
713
  test_framework: z2.string().optional(),
707
714
  test: z2.string().optional(),
708
715
  runtime: z2.string().optional(),
@@ -4035,7 +4042,29 @@ function writeHookContext(hookEventName, message) {
4035
4042
 
4036
4043
  // src/hooks/fix-detector.ts
4037
4044
  init_hook_failure_signal();
4045
+
4046
+ // src/hooks/lib/is-direct-invocation.ts
4047
+ import { pathToFileURL } from "url";
4048
+ function isDirectInvocation(moduleUrl) {
4049
+ const entry = process.argv[1];
4050
+ if (!entry) return false;
4051
+ try {
4052
+ return moduleUrl === pathToFileURL(entry).href;
4053
+ } catch {
4054
+ return false;
4055
+ }
4056
+ }
4057
+
4058
+ // src/hooks/fix-detector.ts
4038
4059
  var HOOK_EVENT = "PostToolUse";
4060
+ var TEST_OR_FIXTURE_PATH_PATTERNS = [
4061
+ /(^|\/)(__tests__|__fixtures__|tests?|fixtures?|spec)\//,
4062
+ /\.(test|spec)\.[cm]?[jt]sx?$/,
4063
+ /(^|\/)(test_[^/]+|[^/]+_test)\.py$/
4064
+ ];
4065
+ function isTestOrFixturePath(filePath) {
4066
+ return TEST_OR_FIXTURE_PATH_PATTERNS.some((re) => re.test(filePath));
4067
+ }
4039
4068
  var FIX_HEURISTICS = [
4040
4069
  {
4041
4070
  name: "removed_broken_code",
@@ -4162,6 +4191,10 @@ async function main() {
4162
4191
  process.exit(0);
4163
4192
  return;
4164
4193
  }
4194
+ if (isTestOrFixturePath(filePath)) {
4195
+ process.exit(0);
4196
+ return;
4197
+ }
4165
4198
  if (config.autoLearning?.enabled === false || config.autoLearning?.fixDetection?.enabled === false) {
4166
4199
  process.exit(0);
4167
4200
  return;
@@ -4231,4 +4264,10 @@ function readStdin() {
4231
4264
  setTimeout(() => resolve5(data), 3e3);
4232
4265
  });
4233
4266
  }
4234
- main();
4267
+ if (isDirectInvocation(import.meta.url)) {
4268
+ main();
4269
+ }
4270
+ export {
4271
+ TEST_OR_FIXTURE_PATH_PATTERNS,
4272
+ isTestOrFixturePath
4273
+ };
@@ -697,6 +697,13 @@ var init_config = __esm({
697
697
  });
698
698
  LanguageFrameworkEntrySchema = z2.object({
699
699
  framework: z2.string().optional(),
700
+ // `source_dirs` is emitted by `init` (commands/init.ts:417) and existence-checked
701
+ // by config validation (init.ts:868-876), but until 2026-08-14 it survived only via
702
+ // `.passthrough()` — declared in the file, untyped in the schema. `lib/source-layout.ts`
703
+ // derives the index builders' candidate set from it, so it is typed here rather than
704
+ // read as an unknown: a consumer that has to shape-check its own SoT is one branch away
705
+ // from silently contributing `undefined` to a path predicate.
706
+ source_dirs: z2.array(z2.string()).optional(),
700
707
  test_framework: z2.string().optional(),
701
708
  test: z2.string().optional(),
702
709
  runtime: z2.string().optional(),
@@ -4028,6 +4035,20 @@ function writeHookContext(hookEventName, message) {
4028
4035
 
4029
4036
  // src/hooks/incident-pipeline.ts
4030
4037
  init_hook_failure_signal();
4038
+
4039
+ // src/hooks/lib/is-direct-invocation.ts
4040
+ import { pathToFileURL } from "url";
4041
+ function isDirectInvocation(moduleUrl) {
4042
+ const entry = process.argv[1];
4043
+ if (!entry) return false;
4044
+ try {
4045
+ return moduleUrl === pathToFileURL(entry).href;
4046
+ } catch {
4047
+ return false;
4048
+ }
4049
+ }
4050
+
4051
+ // src/hooks/incident-pipeline.ts
4031
4052
  var HOOK_EVENT = "PostToolUse";
4032
4053
  async function main() {
4033
4054
  try {
@@ -4155,4 +4176,6 @@ function readStdin() {
4155
4176
  setTimeout(() => resolve6(data), 3e3);
4156
4177
  });
4157
4178
  }
4158
- main();
4179
+ if (isDirectInvocation(import.meta.url)) {
4180
+ main();
4181
+ }
@@ -1167,6 +1167,13 @@ var init_config = __esm({
1167
1167
  });
1168
1168
  LanguageFrameworkEntrySchema = z2.object({
1169
1169
  framework: z2.string().optional(),
1170
+ // `source_dirs` is emitted by `init` (commands/init.ts:417) and existence-checked
1171
+ // by config validation (init.ts:868-876), but until 2026-08-14 it survived only via
1172
+ // `.passthrough()` — declared in the file, untyped in the schema. `lib/source-layout.ts`
1173
+ // derives the index builders' candidate set from it, so it is typed here rather than
1174
+ // read as an unknown: a consumer that has to shape-check its own SoT is one branch away
1175
+ // from silently contributing `undefined` to a path predicate.
1176
+ source_dirs: z2.array(z2.string()).optional(),
1170
1177
  test_framework: z2.string().optional(),
1171
1178
  test: z2.string().optional(),
1172
1179
  runtime: z2.string().optional(),
@@ -4022,6 +4029,20 @@ function writeHookContext(hookEventName, message) {
4022
4029
 
4023
4030
  // src/hooks/intent-suggester.ts
4024
4031
  init_hook_failure_signal();
4032
+
4033
+ // src/hooks/lib/is-direct-invocation.ts
4034
+ import { pathToFileURL } from "url";
4035
+ function isDirectInvocation(moduleUrl) {
4036
+ const entry = process.argv[1];
4037
+ if (!entry) return false;
4038
+ try {
4039
+ return moduleUrl === pathToFileURL(entry).href;
4040
+ } catch {
4041
+ return false;
4042
+ }
4043
+ }
4044
+
4045
+ // src/hooks/intent-suggester.ts
4025
4046
  var HOOK_EVENT = "UserPromptSubmit";
4026
4047
  var COMMAND_MAPPINGS = [
4027
4048
  {
@@ -4117,4 +4138,6 @@ function readStdin() {
4117
4138
  setTimeout(() => resolve5(data), 3e3);
4118
4139
  });
4119
4140
  }
4120
- main();
4141
+ if (isDirectInvocation(import.meta.url)) {
4142
+ main();
4143
+ }
@@ -1167,6 +1167,13 @@ var init_config = __esm({
1167
1167
  });
1168
1168
  LanguageFrameworkEntrySchema = z2.object({
1169
1169
  framework: z2.string().optional(),
1170
+ // `source_dirs` is emitted by `init` (commands/init.ts:417) and existence-checked
1171
+ // by config validation (init.ts:868-876), but until 2026-08-14 it survived only via
1172
+ // `.passthrough()` — declared in the file, untyped in the schema. `lib/source-layout.ts`
1173
+ // derives the index builders' candidate set from it, so it is typed here rather than
1174
+ // read as an unknown: a consumer that has to shape-check its own SoT is one branch away
1175
+ // from silently contributing `undefined` to a path predicate.
1176
+ source_dirs: z2.array(z2.string()).optional(),
1170
1177
  test_framework: z2.string().optional(),
1171
1178
  test: z2.string().optional(),
1172
1179
  runtime: z2.string().optional(),
@@ -4571,6 +4578,20 @@ function writeHookContext(hookEventName, message) {
4571
4578
  init_db_driver();
4572
4579
  init_hook_failure_signal();
4573
4580
  import { existsSync as existsSync9 } from "fs";
4581
+
4582
+ // src/hooks/lib/is-direct-invocation.ts
4583
+ import { pathToFileURL } from "url";
4584
+ function isDirectInvocation(moduleUrl) {
4585
+ const entry = process.argv[1];
4586
+ if (!entry) return false;
4587
+ try {
4588
+ return moduleUrl === pathToFileURL(entry).href;
4589
+ } catch {
4590
+ return false;
4591
+ }
4592
+ }
4593
+
4594
+ // src/hooks/memory-recall.ts
4574
4595
  var HOOK_EVENT = "UserPromptSubmit";
4575
4596
  var DEFAULTS = {
4576
4597
  enabled: true,
@@ -4723,4 +4744,6 @@ function readStdin() {
4723
4744
  setTimeout(() => resolve5(data), 3e3);
4724
4745
  });
4725
4746
  }
4726
- main();
4747
+ if (isDirectInvocation(import.meta.url)) {
4748
+ main();
4749
+ }