UNPKG

paqad-ai

Version:

Spec-driven development framework — AI agents that think before they type

246 lines (242 loc) • 8 kB
import { createRequire as __paqadCreateRequire } from 'module'; const require = __paqadCreateRequire(import.meta.url); import { CAPABILITY_IMPLS, clearRuleStopRecord, frontendTriggerOrFault, isManagedEnv, takeAllowedOnce, visualEvidenceFlagOn, writeRuleStopRecord } from "../chunk-3AKVAXRJ.js"; import "../chunk-E4ZQOAV4.js"; import "../chunk-KXN6TRQP.js"; import "../chunk-Z4GLUCC5.js"; import "../chunk-LGAFOBYN.js"; import "../chunk-WRHJCBRI.js"; import "../chunk-73AIVIC6.js"; import "../chunk-IKAOR4NY.js"; import "../chunk-GCMANDHS.js"; import "../chunk-BKNKG26S.js"; import "../chunk-7Q65STES.js"; import "../chunk-K4E6ACLH.js"; import "../chunk-4ZAWKFXT.js"; import "../chunk-CECHOUNN.js"; import { appendHooksLog } from "../chunk-4S3XFJAH.js"; import "../chunk-HNYZUZ7D.js"; import "../chunk-AK3HYELM.js"; import "../chunk-6XDDIYNJ.js"; import "../chunk-THDANA7U.js"; import "../chunk-I2G54BH7.js"; import { capabilitiesForSeam } from "../chunk-SS625UO5.js"; import { hudLastBlockPath } from "../chunk-3UV6TK6X.js"; import "../chunk-LBNBI3D6.js"; import "../chunk-5ETIY5I3.js"; import "../chunk-UUBQQJVE.js"; import "../chunk-EQYAXXZO.js"; import "../chunk-MDXUST3Z.js"; import "../chunk-22I2D24D.js"; import "../chunk-OAEANL22.js"; import "../chunk-S3UQUJV2.js"; import "../chunk-VOJO7HJ6.js"; import "../chunk-7D5MLTG3.js"; import "../chunk-Y3O45QYV.js"; import "../chunk-P4RPU2KB.js"; import "../chunk-LYNDVGNE.js"; import { currentFeature } from "../chunk-5M55PDWL.js"; import "../chunk-TINPSX3N.js"; import "../chunk-BTDDEK7C.js"; import "../chunk-7TBVBCDH.js"; import "../chunk-RJMJYPHL.js"; import "../chunk-NCYDV2N5.js"; import "../chunk-D6VEUSB6.js"; import "../chunk-BOEVU2BD.js"; import "../chunk-NJE7NS7E.js"; import "../chunk-ACJQW7SB.js"; import "../chunk-YA6SCYMC.js"; import "../chunk-Z3NGWHFX.js"; import "../chunk-YWAORJG6.js"; import "../chunk-Q353EDKY.js"; import { resolveSessionId } from "../chunk-SG6LXLDH.js"; import "../chunk-FMQ5YRSP.js"; import { featureFilePath } from "../chunk-AZLA53A6.js"; import { PATHS } from "../chunk-IHMBVS6H.js"; import { init_esm_shims } from "../chunk-IDFRWBMN.js"; // src/kernel/gate.ts init_esm_shims(); // src/visual-evidence/reminder.ts init_esm_shims(); import { existsSync, mkdirSync, writeFileSync } from "fs"; import { isAbsolute, join, relative } from "path"; var VISUAL_EVIDENCE_REMINDER = "This is a frontend change and visual evidence is on. Before review, run `paqad-ai visual-evidence run` or attach screenshots with `paqad-ai visual-evidence attach`."; var REMINDER_MARKER_DIR = join(PATHS.AGENCY_SESSION_DIR, "visual-evidence-reminded"); function visualEvidenceReminder(input) { const { projectRoot } = input; if (!visualEvidenceFlagOn(projectRoot)) return null; const targets = input.targetPaths.map( (target) => isAbsolute(target) ? relative(projectRoot, target) : target ); if (!frontendTriggerOrFault(projectRoot, targets).triggered) return null; const dirName = currentFeature(projectRoot, resolveSessionId(projectRoot, input.sessionId)); if (!dirName) return null; if (existsSync(join(projectRoot, featureFilePath(dirName, "visualEvidence")))) return null; const marker = join(projectRoot, REMINDER_MARKER_DIR, dirName); try { mkdirSync(join(projectRoot, REMINDER_MARKER_DIR), { recursive: true }); writeFileSync(marker, `${(/* @__PURE__ */ new Date()).toISOString()} `, { encoding: "utf8", flag: "wx" }); } catch { return null; } return VISUAL_EVIDENCE_REMINDER; } // src/kernel/gate.ts var ALLOW_ONCE_REASON = "You allowed this edit once in the paqad HUD, and paqad recorded the override. Approve to run it."; function reminderContext(projectRoot, env, payload) { try { return visualEvidenceReminder({ projectRoot, targetPaths: payload?.targetPaths ?? (payload?.targetPath ? [payload.targetPath] : []), sessionId: payload?.sessionId ?? env.CLAUDE_SESSION_ID ?? null }) ?? ""; } catch { return ""; } } function errorKind(error) { if (error && typeof error === "object" && "code" in error && typeof error.code === "string") { return error.code; } return error instanceof Error ? error.name : "unknown"; } function callerLoadedFramework(entryLoaded) { try { return entryLoaded?.() === true; } catch { return false; } } function syncRuleStopRecord(projectRoot, env, payload, blocking, entryLoaded) { const sessionId = payload?.sessionId ?? env.CLAUDE_SESSION_ID; if (!sessionId) return; const violation = blocking.flatMap((outcome) => outcome.violations ?? [])[0]; const sole = blocking.length === 1 && (blocking[0]?.violations?.length ?? 0) > 0 && callerLoadedFramework(entryLoaded); try { if (!violation) { if (blocking.length === 0) clearRuleStopRecord(projectRoot, sessionId); return; } writeRuleStopRecord({ projectRoot, sessionId, rule: violation.rule_id, title: violation.title ?? null, file: violation.file, toolUseId: payload?.toolUseId ?? null, managed: isManagedEnv(env), sole, toolInput: payload?.toolInput }); } catch (error) { appendHooksLog( projectRoot, `capability-gate rule-stop record not written: ${errorKind(error)} ${hudLastBlockPath(projectRoot, sessionId)}` ); } } function allowedOnce(projectRoot, env, payload, blocking) { try { const sessionId = payload?.sessionId ?? env.CLAUDE_SESSION_ID; if (!sessionId || isManagedEnv(env)) return false; if (payload?.adapter !== void 0 && payload.adapter !== "claude-code") return false; const violations = blocking.length === 1 ? blocking[0]?.violations ?? [] : []; const violation = violations.length === 1 ? violations[0] : void 0; if (!violation) return false; const taken = takeAllowedOnce(projectRoot, sessionId, { toolUseId: payload?.toolUseId, rule: violation.rule_id, file: violation.file }); if (taken) { appendHooksLog( projectRoot, `capability-gate allowed once: asked for ${violation.rule_id} on ${violation.file} (tool_use_id ${payload?.toolUseId})` ); } return taken; } catch (error) { appendHooksLog(projectRoot, `capability-gate allowed-once check failed: ${errorKind(error)}`); return false; } } async function runCapabilityGate(input) { const { projectRoot, seam, env = process.env, payload, entryLoaded, startedAt, now } = input; const outcomes = []; const narrations = []; const contexts = []; for (const descriptor of capabilitiesForSeam(seam)) { const capability = CAPABILITY_IMPLS.get(descriptor.id); if (!capability) { continue; } const outcome = await capability.evaluate({ projectRoot, seam, env, payload, ...startedAt === void 0 ? {} : { startedAt }, ...now ? { now } : {} }); if (outcome.narration) { narrations.push(outcome.narration); } if (outcome.context) { contexts.push(outcome.context); } if (outcome.ran && outcome.summary) { outcomes.push(outcome); } } const narration = narrations.join("\n"); const context = seam === "pre-mutation" ? [...contexts, reminderContext(projectRoot, env, payload)].filter(Boolean).join("\n") : ""; const blocking = outcomes.filter((outcome) => outcome.blocking); if (seam === "pre-mutation" && allowedOnce(projectRoot, env, payload, blocking)) { return { block: false, ask: ALLOW_ONCE_REASON, summary: "", narration, context }; } if (seam === "pre-mutation") { syncRuleStopRecord(projectRoot, env, payload, blocking, entryLoaded); } if (blocking.length > 0) { return { block: true, summary: blocking.map((outcome) => outcome.summary).join("\n"), narration, context }; } return { block: false, summary: outcomes.map((outcome) => outcome.summary).join("\n"), narration, context }; } export { ALLOW_ONCE_REASON, runCapabilityGate };