@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.
- package/CHANGELOG.md +170 -0
- package/dist/cli.js +578 -212
- package/dist/hooks/auto-learning-pipeline.js +244 -47
- package/dist/hooks/classify-failure.js +272 -18
- package/dist/hooks/cost-tracker.js +24 -1
- package/dist/hooks/fix-detector.js +40 -1
- package/dist/hooks/incident-pipeline.js +24 -1
- package/dist/hooks/intent-suggester.js +24 -1
- package/dist/hooks/memory-recall.js +24 -1
- package/dist/hooks/post-edit-context.js +72 -2
- package/dist/hooks/post-tool-use.js +25 -1
- package/dist/hooks/pre-compact.js +24 -1
- package/dist/hooks/pre-delete-check.js +72 -4
- package/dist/hooks/pre-tool-use-gate.js +78 -6
- package/dist/hooks/quality-event.js +24 -1
- package/dist/hooks/rule-enforcement-pipeline.js +24 -1
- package/dist/hooks/security-gate.js +22 -1
- package/dist/hooks/session-end.js +24 -1
- package/dist/hooks/session-start.js +24 -1
- package/dist/hooks/user-prompt.js +24 -1
- package/package.json +1 -1
|
@@ -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
|
|
1818
|
-
return dirname6(
|
|
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
|
|
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
|
|
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/
|
|
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
|
|
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 =
|
|
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 += " " +
|
|
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 =
|
|
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(
|
|
4318
|
+
unlinkSync2(join7(dir, file));
|
|
4071
4319
|
} catch {
|
|
4072
4320
|
}
|
|
4073
4321
|
}
|
|
4074
4322
|
} catch {
|
|
4075
4323
|
}
|
|
4076
4324
|
}
|
|
4077
|
-
async function
|
|
4325
|
+
async function main2() {
|
|
4078
4326
|
try {
|
|
4079
|
-
const input = await
|
|
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 (
|
|
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(
|
|
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(
|
|
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(
|
|
4450
|
+
writeHookContext(HOOK_EVENT2, lines.join("\n"));
|
|
4199
4451
|
}
|
|
4200
|
-
function
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
4747
|
+
if (isDirectInvocation(import.meta.url)) {
|
|
4748
|
+
main();
|
|
4749
|
+
}
|