@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
|
@@ -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(),
|
|
@@ -4016,6 +4023,53 @@ function t(suffix) {
|
|
|
4016
4023
|
return `${getConfig().toolPrefix}_${suffix}`;
|
|
4017
4024
|
}
|
|
4018
4025
|
|
|
4026
|
+
// src/lib/source-layout.ts
|
|
4027
|
+
init_config();
|
|
4028
|
+
function normalizeDir(raw) {
|
|
4029
|
+
if (typeof raw !== "string") return null;
|
|
4030
|
+
const posix = raw.replace(/\\/g, "/");
|
|
4031
|
+
if (posix.startsWith("/") || /^[A-Za-z]:\//.test(posix)) return null;
|
|
4032
|
+
const parts = posix.split("/").filter((p) => p !== "" && p !== ".");
|
|
4033
|
+
if (parts.some((p) => p === "..")) return null;
|
|
4034
|
+
if (parts.length === 0) return ".";
|
|
4035
|
+
return parts.join("/");
|
|
4036
|
+
}
|
|
4037
|
+
function declaredLanguageSourceDirs() {
|
|
4038
|
+
const languages = getConfig().framework.languages;
|
|
4039
|
+
if (!languages) return [];
|
|
4040
|
+
const out = [];
|
|
4041
|
+
for (const entry of Object.values(languages)) {
|
|
4042
|
+
if (Array.isArray(entry.source_dirs)) out.push(...entry.source_dirs);
|
|
4043
|
+
}
|
|
4044
|
+
return out;
|
|
4045
|
+
}
|
|
4046
|
+
function getSourceLayout() {
|
|
4047
|
+
const config = getConfig();
|
|
4048
|
+
const paths = config.paths;
|
|
4049
|
+
const declared = [
|
|
4050
|
+
paths.source,
|
|
4051
|
+
...paths.monorepo_roots ?? [],
|
|
4052
|
+
...declaredLanguageSourceDirs()
|
|
4053
|
+
];
|
|
4054
|
+
const normalized = declared.map(normalizeDir).filter((d) => d !== null);
|
|
4055
|
+
const includesRoot = normalized.includes(".");
|
|
4056
|
+
const sourceDirs = includesRoot ? [] : [...new Set(normalized)].sort();
|
|
4057
|
+
const source = normalizeDir(paths.source) ?? ".";
|
|
4058
|
+
const under = (child) => source === "." ? child : `${source}/${child}`;
|
|
4059
|
+
return {
|
|
4060
|
+
sourceDirs,
|
|
4061
|
+
includesRoot,
|
|
4062
|
+
extensions: getResolvedPaths().extensions,
|
|
4063
|
+
pagesDir: normalizeDir(paths.pages ?? under("app")) ?? under("app"),
|
|
4064
|
+
componentsDir: normalizeDir(paths.components ?? under("components")) ?? under("components")
|
|
4065
|
+
};
|
|
4066
|
+
}
|
|
4067
|
+
function isUnderSourceDir(path, layout = getSourceLayout()) {
|
|
4068
|
+
if (normalizeDir(path) === null) return false;
|
|
4069
|
+
if (layout.includesRoot) return true;
|
|
4070
|
+
return layout.sourceDirs.some((d) => path.startsWith(`${d}/`));
|
|
4071
|
+
}
|
|
4072
|
+
|
|
4019
4073
|
// src/middleware-tree.ts
|
|
4020
4074
|
function isInMiddlewareTree(dataDb, file) {
|
|
4021
4075
|
const result = dataDb.prepare(`SELECT 1 FROM ${t("middleware_tree")} WHERE file = ?`).get(file);
|
|
@@ -4062,6 +4116,20 @@ function writeHookContext(hookEventName, message) {
|
|
|
4062
4116
|
|
|
4063
4117
|
// src/hooks/post-edit-context.ts
|
|
4064
4118
|
init_hook_failure_signal();
|
|
4119
|
+
|
|
4120
|
+
// src/hooks/lib/is-direct-invocation.ts
|
|
4121
|
+
import { pathToFileURL } from "url";
|
|
4122
|
+
function isDirectInvocation(moduleUrl) {
|
|
4123
|
+
const entry = process.argv[1];
|
|
4124
|
+
if (!entry) return false;
|
|
4125
|
+
try {
|
|
4126
|
+
return moduleUrl === pathToFileURL(entry).href;
|
|
4127
|
+
} catch {
|
|
4128
|
+
return false;
|
|
4129
|
+
}
|
|
4130
|
+
}
|
|
4131
|
+
|
|
4132
|
+
// src/hooks/post-edit-context.ts
|
|
4065
4133
|
var HOOK_EVENT = "PostToolUse";
|
|
4066
4134
|
async function main() {
|
|
4067
4135
|
try {
|
|
@@ -4074,7 +4142,7 @@ async function main() {
|
|
|
4074
4142
|
}
|
|
4075
4143
|
const root = getProjectRoot();
|
|
4076
4144
|
const rel = filePath.startsWith(root + "/") ? filePath.slice(root.length + 1) : filePath;
|
|
4077
|
-
if (!rel
|
|
4145
|
+
if (!isUnderSourceDir(rel) && !rel.endsWith(".py")) {
|
|
4078
4146
|
process.exit(0);
|
|
4079
4147
|
return;
|
|
4080
4148
|
}
|
|
@@ -4117,4 +4185,6 @@ function readStdin() {
|
|
|
4117
4185
|
setTimeout(() => resolve5(data), 3e3);
|
|
4118
4186
|
});
|
|
4119
4187
|
}
|
|
4120
|
-
|
|
4188
|
+
if (isDirectInvocation(import.meta.url)) {
|
|
4189
|
+
main();
|
|
4190
|
+
}
|
|
@@ -1173,6 +1173,13 @@ var init_config = __esm({
|
|
|
1173
1173
|
});
|
|
1174
1174
|
LanguageFrameworkEntrySchema = z2.object({
|
|
1175
1175
|
framework: z2.string().optional(),
|
|
1176
|
+
// `source_dirs` is emitted by `init` (commands/init.ts:417) and existence-checked
|
|
1177
|
+
// by config validation (init.ts:868-876), but until 2026-08-14 it survived only via
|
|
1178
|
+
// `.passthrough()` — declared in the file, untyped in the schema. `lib/source-layout.ts`
|
|
1179
|
+
// derives the index builders' candidate set from it, so it is typed here rather than
|
|
1180
|
+
// read as an unknown: a consumer that has to shape-check its own SoT is one branch away
|
|
1181
|
+
// from silently contributing `undefined` to a path predicate.
|
|
1182
|
+
source_dirs: z2.array(z2.string()).optional(),
|
|
1176
1183
|
test_framework: z2.string().optional(),
|
|
1177
1184
|
test: z2.string().optional(),
|
|
1178
1185
|
runtime: z2.string().optional(),
|
|
@@ -4471,6 +4478,9 @@ function enforceSeverityFloors(configWeights, defaults) {
|
|
|
4471
4478
|
// src/lib/sql-table-names.ts
|
|
4472
4479
|
init_config();
|
|
4473
4480
|
|
|
4481
|
+
// src/lib/source-layout.ts
|
|
4482
|
+
init_config();
|
|
4483
|
+
|
|
4474
4484
|
// src/import-resolver.ts
|
|
4475
4485
|
function resolveImportPath(specifier, fromFile) {
|
|
4476
4486
|
if (!specifier.startsWith(".") && !specifier.startsWith("@/")) {
|
|
@@ -5046,6 +5056,18 @@ function mapMemoryTypeToObservationType(memoryType) {
|
|
|
5046
5056
|
}
|
|
5047
5057
|
}
|
|
5048
5058
|
|
|
5059
|
+
// src/hooks/lib/is-direct-invocation.ts
|
|
5060
|
+
import { pathToFileURL } from "url";
|
|
5061
|
+
function isDirectInvocation(moduleUrl) {
|
|
5062
|
+
const entry = process.argv[1];
|
|
5063
|
+
if (!entry) return false;
|
|
5064
|
+
try {
|
|
5065
|
+
return moduleUrl === pathToFileURL(entry).href;
|
|
5066
|
+
} catch {
|
|
5067
|
+
return false;
|
|
5068
|
+
}
|
|
5069
|
+
}
|
|
5070
|
+
|
|
5049
5071
|
// src/hooks/post-tool-use.ts
|
|
5050
5072
|
var _yamlParser = null;
|
|
5051
5073
|
var parseYaml3 = (content) => {
|
|
@@ -5384,4 +5406,6 @@ function checkMemoryFileIntegrity(filePath) {
|
|
|
5384
5406
|
}
|
|
5385
5407
|
return issues;
|
|
5386
5408
|
}
|
|
5387
|
-
|
|
5409
|
+
if (isDirectInvocation(import.meta.url)) {
|
|
5410
|
+
main();
|
|
5411
|
+
}
|
|
@@ -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(),
|
|
@@ -4010,6 +4017,20 @@ function logAuditEntry(db, entry) {
|
|
|
4010
4017
|
|
|
4011
4018
|
// src/hooks/pre-compact.ts
|
|
4012
4019
|
init_hook_failure_signal();
|
|
4020
|
+
|
|
4021
|
+
// src/hooks/lib/is-direct-invocation.ts
|
|
4022
|
+
import { pathToFileURL } from "url";
|
|
4023
|
+
function isDirectInvocation(moduleUrl) {
|
|
4024
|
+
const entry = process.argv[1];
|
|
4025
|
+
if (!entry) return false;
|
|
4026
|
+
try {
|
|
4027
|
+
return moduleUrl === pathToFileURL(entry).href;
|
|
4028
|
+
} catch {
|
|
4029
|
+
return false;
|
|
4030
|
+
}
|
|
4031
|
+
}
|
|
4032
|
+
|
|
4033
|
+
// src/hooks/pre-compact.ts
|
|
4013
4034
|
async function main() {
|
|
4014
4035
|
try {
|
|
4015
4036
|
const input = await readStdin();
|
|
@@ -4116,4 +4137,6 @@ function readStdin() {
|
|
|
4116
4137
|
setTimeout(() => resolve5(data), 3e3);
|
|
4117
4138
|
});
|
|
4118
4139
|
}
|
|
4119
|
-
|
|
4140
|
+
if (isDirectInvocation(import.meta.url)) {
|
|
4141
|
+
main();
|
|
4142
|
+
}
|
|
@@ -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(),
|
|
@@ -4084,6 +4091,53 @@ function getFeatureImpact(db, filePaths) {
|
|
|
4084
4091
|
// src/hooks/pre-delete-check.ts
|
|
4085
4092
|
init_config();
|
|
4086
4093
|
|
|
4094
|
+
// src/lib/source-layout.ts
|
|
4095
|
+
init_config();
|
|
4096
|
+
function normalizeDir(raw) {
|
|
4097
|
+
if (typeof raw !== "string") return null;
|
|
4098
|
+
const posix = raw.replace(/\\/g, "/");
|
|
4099
|
+
if (posix.startsWith("/") || /^[A-Za-z]:\//.test(posix)) return null;
|
|
4100
|
+
const parts = posix.split("/").filter((p) => p !== "" && p !== ".");
|
|
4101
|
+
if (parts.some((p) => p === "..")) return null;
|
|
4102
|
+
if (parts.length === 0) return ".";
|
|
4103
|
+
return parts.join("/");
|
|
4104
|
+
}
|
|
4105
|
+
function declaredLanguageSourceDirs() {
|
|
4106
|
+
const languages = getConfig().framework.languages;
|
|
4107
|
+
if (!languages) return [];
|
|
4108
|
+
const out = [];
|
|
4109
|
+
for (const entry of Object.values(languages)) {
|
|
4110
|
+
if (Array.isArray(entry.source_dirs)) out.push(...entry.source_dirs);
|
|
4111
|
+
}
|
|
4112
|
+
return out;
|
|
4113
|
+
}
|
|
4114
|
+
function getSourceLayout() {
|
|
4115
|
+
const config = getConfig();
|
|
4116
|
+
const paths = config.paths;
|
|
4117
|
+
const declared = [
|
|
4118
|
+
paths.source,
|
|
4119
|
+
...paths.monorepo_roots ?? [],
|
|
4120
|
+
...declaredLanguageSourceDirs()
|
|
4121
|
+
];
|
|
4122
|
+
const normalized = declared.map(normalizeDir).filter((d) => d !== null);
|
|
4123
|
+
const includesRoot = normalized.includes(".");
|
|
4124
|
+
const sourceDirs = includesRoot ? [] : [...new Set(normalized)].sort();
|
|
4125
|
+
const source = normalizeDir(paths.source) ?? ".";
|
|
4126
|
+
const under = (child) => source === "." ? child : `${source}/${child}`;
|
|
4127
|
+
return {
|
|
4128
|
+
sourceDirs,
|
|
4129
|
+
includesRoot,
|
|
4130
|
+
extensions: getResolvedPaths().extensions,
|
|
4131
|
+
pagesDir: normalizeDir(paths.pages ?? under("app")) ?? under("app"),
|
|
4132
|
+
componentsDir: normalizeDir(paths.components ?? under("components")) ?? under("components")
|
|
4133
|
+
};
|
|
4134
|
+
}
|
|
4135
|
+
function isUnderSourceDir(path, layout = getSourceLayout()) {
|
|
4136
|
+
if (normalizeDir(path) === null) return false;
|
|
4137
|
+
if (layout.includesRoot) return true;
|
|
4138
|
+
return layout.sourceDirs.some((d) => path.startsWith(`${d}/`));
|
|
4139
|
+
}
|
|
4140
|
+
|
|
4087
4141
|
// src/hooks/lib/write-hook-message.ts
|
|
4088
4142
|
var HOOK_EVENTS = [
|
|
4089
4143
|
"UserPromptSubmit",
|
|
@@ -4121,6 +4175,20 @@ function writeHookContext(hookEventName, message) {
|
|
|
4121
4175
|
|
|
4122
4176
|
// src/hooks/pre-delete-check.ts
|
|
4123
4177
|
init_hook_failure_signal();
|
|
4178
|
+
|
|
4179
|
+
// src/hooks/lib/is-direct-invocation.ts
|
|
4180
|
+
import { pathToFileURL } from "url";
|
|
4181
|
+
function isDirectInvocation(moduleUrl) {
|
|
4182
|
+
const entry = process.argv[1];
|
|
4183
|
+
if (!entry) return false;
|
|
4184
|
+
try {
|
|
4185
|
+
return moduleUrl === pathToFileURL(entry).href;
|
|
4186
|
+
} catch {
|
|
4187
|
+
return false;
|
|
4188
|
+
}
|
|
4189
|
+
}
|
|
4190
|
+
|
|
4191
|
+
// src/hooks/pre-delete-check.ts
|
|
4124
4192
|
var HOOK_EVENT = "PreToolUse";
|
|
4125
4193
|
var PROJECT_ROOT2 = getProjectRoot();
|
|
4126
4194
|
var KNOWLEDGE_PROTECTED_FILES = [
|
|
@@ -4171,8 +4239,8 @@ function extractDeletedFiles(input) {
|
|
|
4171
4239
|
if (rmMatch) {
|
|
4172
4240
|
const paths = rmMatch[1].split(/\s+/).filter((p) => !p.startsWith("-"));
|
|
4173
4241
|
for (const p of paths) {
|
|
4174
|
-
const relPath = p
|
|
4175
|
-
if (relPath
|
|
4242
|
+
const relPath = isUnderSourceDir(p) ? p : p.replace(PROJECT_ROOT2 + "/", "");
|
|
4243
|
+
if (isUnderSourceDir(relPath) || relPath.endsWith(".py")) {
|
|
4176
4244
|
files.push(relPath);
|
|
4177
4245
|
}
|
|
4178
4246
|
}
|
|
@@ -4182,7 +4250,7 @@ function extractDeletedFiles(input) {
|
|
|
4182
4250
|
const content = input.tool_input.content || "";
|
|
4183
4251
|
if (content.trim().length === 0) {
|
|
4184
4252
|
const relPath = input.tool_input.file_path.replace(PROJECT_ROOT2 + "/", "");
|
|
4185
|
-
if (relPath
|
|
4253
|
+
if (isUnderSourceDir(relPath) || relPath.endsWith(".py")) {
|
|
4186
4254
|
files.push(relPath);
|
|
4187
4255
|
}
|
|
4188
4256
|
}
|
|
@@ -4284,7 +4352,7 @@ function readStdin() {
|
|
|
4284
4352
|
setTimeout(() => resolve5(data), 400);
|
|
4285
4353
|
});
|
|
4286
4354
|
}
|
|
4287
|
-
if (
|
|
4355
|
+
if (isDirectInvocation(import.meta.url)) {
|
|
4288
4356
|
main();
|
|
4289
4357
|
}
|
|
4290
4358
|
export {
|
|
@@ -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/security-gate.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/security-gate.ts
|
|
4025
4046
|
var HOOK_EVENT = "PreToolUse";
|
|
4026
4047
|
var DANGEROUS_BASH_PATTERNS = [
|
|
4027
4048
|
// BLOCK — destructive and irreversible, or arbitrary remote code execution.
|
|
@@ -4161,7 +4182,7 @@ function readStdin() {
|
|
|
4161
4182
|
setTimeout(() => resolve5(data), 400);
|
|
4162
4183
|
});
|
|
4163
4184
|
}
|
|
4164
|
-
if (
|
|
4185
|
+
if (isDirectInvocation(import.meta.url)) {
|
|
4165
4186
|
main();
|
|
4166
4187
|
}
|
|
4167
4188
|
|
|
@@ -4263,6 +4284,55 @@ function getFeatureImpact(db, filePaths) {
|
|
|
4263
4284
|
|
|
4264
4285
|
// src/hooks/pre-delete-check.ts
|
|
4265
4286
|
init_config();
|
|
4287
|
+
|
|
4288
|
+
// src/lib/source-layout.ts
|
|
4289
|
+
init_config();
|
|
4290
|
+
function normalizeDir(raw) {
|
|
4291
|
+
if (typeof raw !== "string") return null;
|
|
4292
|
+
const posix = raw.replace(/\\/g, "/");
|
|
4293
|
+
if (posix.startsWith("/") || /^[A-Za-z]:\//.test(posix)) return null;
|
|
4294
|
+
const parts = posix.split("/").filter((p) => p !== "" && p !== ".");
|
|
4295
|
+
if (parts.some((p) => p === "..")) return null;
|
|
4296
|
+
if (parts.length === 0) return ".";
|
|
4297
|
+
return parts.join("/");
|
|
4298
|
+
}
|
|
4299
|
+
function declaredLanguageSourceDirs() {
|
|
4300
|
+
const languages = getConfig().framework.languages;
|
|
4301
|
+
if (!languages) return [];
|
|
4302
|
+
const out = [];
|
|
4303
|
+
for (const entry of Object.values(languages)) {
|
|
4304
|
+
if (Array.isArray(entry.source_dirs)) out.push(...entry.source_dirs);
|
|
4305
|
+
}
|
|
4306
|
+
return out;
|
|
4307
|
+
}
|
|
4308
|
+
function getSourceLayout() {
|
|
4309
|
+
const config = getConfig();
|
|
4310
|
+
const paths = config.paths;
|
|
4311
|
+
const declared = [
|
|
4312
|
+
paths.source,
|
|
4313
|
+
...paths.monorepo_roots ?? [],
|
|
4314
|
+
...declaredLanguageSourceDirs()
|
|
4315
|
+
];
|
|
4316
|
+
const normalized = declared.map(normalizeDir).filter((d) => d !== null);
|
|
4317
|
+
const includesRoot = normalized.includes(".");
|
|
4318
|
+
const sourceDirs = includesRoot ? [] : [...new Set(normalized)].sort();
|
|
4319
|
+
const source = normalizeDir(paths.source) ?? ".";
|
|
4320
|
+
const under = (child) => source === "." ? child : `${source}/${child}`;
|
|
4321
|
+
return {
|
|
4322
|
+
sourceDirs,
|
|
4323
|
+
includesRoot,
|
|
4324
|
+
extensions: getResolvedPaths().extensions,
|
|
4325
|
+
pagesDir: normalizeDir(paths.pages ?? under("app")) ?? under("app"),
|
|
4326
|
+
componentsDir: normalizeDir(paths.components ?? under("components")) ?? under("components")
|
|
4327
|
+
};
|
|
4328
|
+
}
|
|
4329
|
+
function isUnderSourceDir(path, layout = getSourceLayout()) {
|
|
4330
|
+
if (normalizeDir(path) === null) return false;
|
|
4331
|
+
if (layout.includesRoot) return true;
|
|
4332
|
+
return layout.sourceDirs.some((d) => path.startsWith(`${d}/`));
|
|
4333
|
+
}
|
|
4334
|
+
|
|
4335
|
+
// src/hooks/pre-delete-check.ts
|
|
4266
4336
|
init_hook_failure_signal();
|
|
4267
4337
|
var HOOK_EVENT2 = "PreToolUse";
|
|
4268
4338
|
var PROJECT_ROOT2 = getProjectRoot();
|
|
@@ -4314,8 +4384,8 @@ function extractDeletedFiles(input) {
|
|
|
4314
4384
|
if (rmMatch) {
|
|
4315
4385
|
const paths = rmMatch[1].split(/\s+/).filter((p) => !p.startsWith("-"));
|
|
4316
4386
|
for (const p of paths) {
|
|
4317
|
-
const relPath = p
|
|
4318
|
-
if (relPath
|
|
4387
|
+
const relPath = isUnderSourceDir(p) ? p : p.replace(PROJECT_ROOT2 + "/", "");
|
|
4388
|
+
if (isUnderSourceDir(relPath) || relPath.endsWith(".py")) {
|
|
4319
4389
|
files.push(relPath);
|
|
4320
4390
|
}
|
|
4321
4391
|
}
|
|
@@ -4325,7 +4395,7 @@ function extractDeletedFiles(input) {
|
|
|
4325
4395
|
const content = input.tool_input.content || "";
|
|
4326
4396
|
if (content.trim().length === 0) {
|
|
4327
4397
|
const relPath = input.tool_input.file_path.replace(PROJECT_ROOT2 + "/", "");
|
|
4328
|
-
if (relPath
|
|
4398
|
+
if (isUnderSourceDir(relPath) || relPath.endsWith(".py")) {
|
|
4329
4399
|
files.push(relPath);
|
|
4330
4400
|
}
|
|
4331
4401
|
}
|
|
@@ -4427,7 +4497,7 @@ function readStdin2() {
|
|
|
4427
4497
|
setTimeout(() => resolve5(data), 400);
|
|
4428
4498
|
});
|
|
4429
4499
|
}
|
|
4430
|
-
if (
|
|
4500
|
+
if (isDirectInvocation(import.meta.url)) {
|
|
4431
4501
|
main2();
|
|
4432
4502
|
}
|
|
4433
4503
|
|
|
@@ -4525,4 +4595,6 @@ async function main3() {
|
|
|
4525
4595
|
}
|
|
4526
4596
|
process.exit(EXIT_ALLOW);
|
|
4527
4597
|
}
|
|
4528
|
-
|
|
4598
|
+
if (isDirectInvocation(import.meta.url)) {
|
|
4599
|
+
main3();
|
|
4600
|
+
}
|
|
@@ -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/quality-event.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/quality-event.ts
|
|
4089
4110
|
var TEST_FAILURE_PATTERNS = [
|
|
4090
4111
|
/\bFAIL\b/,
|
|
4091
4112
|
/✗/,
|
|
@@ -4174,4 +4195,6 @@ function readStdin() {
|
|
|
4174
4195
|
setTimeout(() => resolve5(data), 3e3);
|
|
4175
4196
|
});
|
|
4176
4197
|
}
|
|
4177
|
-
|
|
4198
|
+
if (isDirectInvocation(import.meta.url)) {
|
|
4199
|
+
main();
|
|
4200
|
+
}
|
|
@@ -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(),
|
|
@@ -4027,6 +4034,20 @@ function writeHookContext(hookEventName, message) {
|
|
|
4027
4034
|
|
|
4028
4035
|
// src/hooks/rule-enforcement-pipeline.ts
|
|
4029
4036
|
init_hook_failure_signal();
|
|
4037
|
+
|
|
4038
|
+
// src/hooks/lib/is-direct-invocation.ts
|
|
4039
|
+
import { pathToFileURL } from "url";
|
|
4040
|
+
function isDirectInvocation(moduleUrl) {
|
|
4041
|
+
const entry = process.argv[1];
|
|
4042
|
+
if (!entry) return false;
|
|
4043
|
+
try {
|
|
4044
|
+
return moduleUrl === pathToFileURL(entry).href;
|
|
4045
|
+
} catch {
|
|
4046
|
+
return false;
|
|
4047
|
+
}
|
|
4048
|
+
}
|
|
4049
|
+
|
|
4050
|
+
// src/hooks/rule-enforcement-pipeline.ts
|
|
4030
4051
|
var HOOK_EVENT = "PostToolUse";
|
|
4031
4052
|
async function main() {
|
|
4032
4053
|
try {
|
|
@@ -4142,4 +4163,6 @@ function readStdin() {
|
|
|
4142
4163
|
setTimeout(() => resolve6(data), 3e3);
|
|
4143
4164
|
});
|
|
4144
4165
|
}
|
|
4145
|
-
|
|
4166
|
+
if (isDirectInvocation(import.meta.url)) {
|
|
4167
|
+
main();
|
|
4168
|
+
}
|
|
@@ -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/security-gate.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/security-gate.ts
|
|
4025
4046
|
var HOOK_EVENT = "PreToolUse";
|
|
4026
4047
|
var DANGEROUS_BASH_PATTERNS = [
|
|
4027
4048
|
// BLOCK — destructive and irreversible, or arbitrary remote code execution.
|
|
@@ -4161,7 +4182,7 @@ function readStdin() {
|
|
|
4161
4182
|
setTimeout(() => resolve5(data), 400);
|
|
4162
4183
|
});
|
|
4163
4184
|
}
|
|
4164
|
-
if (
|
|
4185
|
+
if (isDirectInvocation(import.meta.url)) {
|
|
4165
4186
|
main();
|
|
4166
4187
|
}
|
|
4167
4188
|
export {
|
|
@@ -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(),
|
|
@@ -7361,6 +7368,20 @@ async function runConsolidation(db, opts = {}) {
|
|
|
7361
7368
|
|
|
7362
7369
|
// src/hooks/session-end.ts
|
|
7363
7370
|
init_hook_failure_signal();
|
|
7371
|
+
|
|
7372
|
+
// src/hooks/lib/is-direct-invocation.ts
|
|
7373
|
+
import { pathToFileURL } from "url";
|
|
7374
|
+
function isDirectInvocation(moduleUrl) {
|
|
7375
|
+
const entry = process.argv[1];
|
|
7376
|
+
if (!entry) return false;
|
|
7377
|
+
try {
|
|
7378
|
+
return moduleUrl === pathToFileURL(entry).href;
|
|
7379
|
+
} catch {
|
|
7380
|
+
return false;
|
|
7381
|
+
}
|
|
7382
|
+
}
|
|
7383
|
+
|
|
7384
|
+
// src/hooks/session-end.ts
|
|
7364
7385
|
async function main() {
|
|
7365
7386
|
try {
|
|
7366
7387
|
const input = await readStdin();
|
|
@@ -7720,4 +7741,6 @@ function readStdin() {
|
|
|
7720
7741
|
setTimeout(() => resolve8(data), 5e3);
|
|
7721
7742
|
});
|
|
7722
7743
|
}
|
|
7723
|
-
|
|
7744
|
+
if (isDirectInvocation(import.meta.url)) {
|
|
7745
|
+
main();
|
|
7746
|
+
}
|
|
@@ -1190,6 +1190,13 @@ var init_config = __esm({
|
|
|
1190
1190
|
});
|
|
1191
1191
|
LanguageFrameworkEntrySchema = z2.object({
|
|
1192
1192
|
framework: z2.string().optional(),
|
|
1193
|
+
// `source_dirs` is emitted by `init` (commands/init.ts:417) and existence-checked
|
|
1194
|
+
// by config validation (init.ts:868-876), but until 2026-08-14 it survived only via
|
|
1195
|
+
// `.passthrough()` — declared in the file, untyped in the schema. `lib/source-layout.ts`
|
|
1196
|
+
// derives the index builders' candidate set from it, so it is typed here rather than
|
|
1197
|
+
// read as an unknown: a consumer that has to shape-check its own SoT is one branch away
|
|
1198
|
+
// from silently contributing `undefined` to a path predicate.
|
|
1199
|
+
source_dirs: z2.array(z2.string()).optional(),
|
|
1193
1200
|
test_framework: z2.string().optional(),
|
|
1194
1201
|
test: z2.string().optional(),
|
|
1195
1202
|
runtime: z2.string().optional(),
|
|
@@ -14188,6 +14195,20 @@ function checkWindows(pid) {
|
|
|
14188
14195
|
|
|
14189
14196
|
// src/hooks/session-start.ts
|
|
14190
14197
|
init_hook_failure_signal();
|
|
14198
|
+
|
|
14199
|
+
// src/hooks/lib/is-direct-invocation.ts
|
|
14200
|
+
import { pathToFileURL } from "url";
|
|
14201
|
+
function isDirectInvocation(moduleUrl) {
|
|
14202
|
+
const entry = process.argv[1];
|
|
14203
|
+
if (!entry) return false;
|
|
14204
|
+
try {
|
|
14205
|
+
return moduleUrl === pathToFileURL(entry).href;
|
|
14206
|
+
} catch {
|
|
14207
|
+
return false;
|
|
14208
|
+
}
|
|
14209
|
+
}
|
|
14210
|
+
|
|
14211
|
+
// src/hooks/session-start.ts
|
|
14191
14212
|
async function main() {
|
|
14192
14213
|
try {
|
|
14193
14214
|
const input = await readStdin();
|
|
@@ -14546,7 +14567,9 @@ function formatAge(ms) {
|
|
|
14546
14567
|
const hr = Math.round(min / 60);
|
|
14547
14568
|
return `${hr}h`;
|
|
14548
14569
|
}
|
|
14549
|
-
|
|
14570
|
+
if (isDirectInvocation(import.meta.url)) {
|
|
14571
|
+
main();
|
|
14572
|
+
}
|
|
14550
14573
|
/*! Bundled license information:
|
|
14551
14574
|
|
|
14552
14575
|
is-extglob/index.js:
|