Fix CSP and hook ancestor discovery

Recognize Next.js 16 proxy files when detecting runtime CSP and mirror harness ancestor lookup when locating active hook manifests for nested projects.

AI assistance disclosure: Implemented and verified with Codex under maintainer direction.
This commit is contained in:
Paul Bakaus
2026-09-02 09:13:53 -07:00
parent a264199177
commit be43532192
8 changed files with 109 additions and 6 deletions
+34 -2
View File
@@ -1313,6 +1313,39 @@ function hookEnabledAt(root) {
const STOP_REVIEW_PROVIDERS = new Set(['claude-code', 'codex', 'agents', 'grok']);
// Harness project settings are discovered by walking up from the active
// working directory. Context resolution can intentionally select a nested
// product root even when the harness project (and its hook manifest) lives at
// the enclosing git root, so checking only projectRoot/repoRoot produces a
// false MANUAL_DETECTOR_REQUIRED directive. Mirror the ancestor lookup through
// the nearest git boundary, while retaining exact resolved roots for explicit
// targets outside the invoking directory.
function hookManifestSearchRoots(ctx) {
const roots = [];
const seen = new Set();
const add = (root) => {
if (!root) return;
const resolved = path.resolve(root);
if (seen.has(resolved)) return;
seen.add(resolved);
roots.push(resolved);
};
let current = path.resolve(process.cwd());
const home = path.resolve(os.homedir());
while (true) {
add(current);
if (current === home || hasGitBoundary(current)) break;
const parent = path.dirname(current);
if (parent === current) break;
current = parent;
}
add(ctx.projectRoot);
add(ctx.repoRoot);
return roots;
}
function automaticHookMode(ctx) {
if (ctx.platform === 'ios' || ctx.platform === 'android' || ctx.platform === 'adaptive') {
return 'none';
@@ -1320,8 +1353,7 @@ function automaticHookMode(ctx) {
const activeRoot = path.resolve(ctx.projectRoot || process.cwd());
if (!hookEnabledAt(activeRoot)) return 'none';
const manifests = HOOK_MANIFESTS_BY_PROVIDER[IMPECCABLE_PROVIDER_ID] || [];
const roots = [...new Set([process.cwd(), ctx.projectRoot, ctx.repoRoot].filter(Boolean).map((root) => path.resolve(root)))];
for (const root of roots) {
for (const root of hookManifestSearchRoots(ctx)) {
for (const rel of manifests) {
const raw = readJson(path.join(root, rel));
if (raw?.hooks && valueHasHookMarker(raw.hooks)) {