import { isAbsolute, relative, resolve } from 'node:path';
import compact from 'lodash/compact.js';
import uniq from 'lodash/uniq.js';
const PATH_OUTPUT_MUTATION_OPERATIONS = new Set(['write', 'delete', 'move', 'execute', 'git', 'unknown']);
/**
 * Builds post-execution audit records for unattended autopilot tool calls.
 *
 * This service owns the autonomy-domain interpretation of observed tool output.
 * It does not execute tools and it does not make host/UI decisions.
 */
export class AutonomyPostflightAuditService {
    static shouldAudit(evaluation) {
        return evaluation?.profileMode === 'autopilot' && evaluation.decision.type === 'allow';
    }
    static create(args) {
        const workspaceRoot = resolve(args.workspaceRoot ?? args.evaluation.facts.cwd ?? process.cwd());
        const changedPaths = AutonomyPostflightAuditService.extractChangedPaths({
            output: args.result.output,
            operations: args.evaluation.facts.operations,
            workspaceRoot,
        });
        const changedRoots = AutonomyPostflightAuditService.resolveChangedRoots({
            changedPaths,
            declaredWriteRoots: args.evaluation.facts.claimedWriteRoots,
        });
        const exceededDeclaredRoots = AutonomyPostflightAuditService.resolveExceededDeclaredRoots({
            changedPaths,
            declaredWriteRoots: args.evaluation.facts.claimedWriteRoots,
        });
        const gitHistoryChanged = AutonomyPostflightAuditService.detectGitHistoryChange(args.evaluation.facts.command);
        const decision = exceededDeclaredRoots.length > 0 || gitHistoryChanged ? 'stop' : 'continue';
        return {
            call: args.evaluation.call,
            envelope: args.evaluation.envelope,
            observedEffects: {
                changedPaths,
                changedRoots,
                exceededDeclaredRoots,
                gitHistoryChanged,
            },
            decision,
            reason: AutonomyPostflightAuditService.formatReason({
                changedPaths,
                exceededDeclaredRoots,
                gitHistoryChanged,
                decision,
            }),
        };
    }
    static extractChangedPaths(args) {
        if (!isRecord(args.output)) {
            return [];
        }
        const shouldInterpretPathOutputAsMutation = args.operations.some((operation) => PATH_OUTPUT_MUTATION_OPERATIONS.has(operation));
        const changedPaths = [
            ...AutonomyPostflightAuditService.stringArray(args.output.changedPaths),
            ...(shouldInterpretPathOutputAsMutation
                ? [
                    AutonomyPostflightAuditService.stringValue(args.output.path),
                    AutonomyPostflightAuditService.stringValue(args.output.from),
                    AutonomyPostflightAuditService.stringValue(args.output.to),
                ]
                : []),
        ];
        return uniq(compact(changedPaths).map((path) => resolve(args.workspaceRoot, path)));
    }
    static resolveChangedRoots(args) {
        return uniq(args.changedPaths.map((changedPath) => AutonomyPostflightAuditService.findContainingRoot({
            path: changedPath,
            roots: args.declaredWriteRoots,
        }) ?? changedPath));
    }
    static resolveExceededDeclaredRoots(args) {
        if (args.changedPaths.length === 0) {
            return [];
        }
        return args.changedPaths.filter((changedPath) => !AutonomyPostflightAuditService.findContainingRoot({
            path: changedPath,
            roots: args.declaredWriteRoots,
        }));
    }
    static findContainingRoot(args) {
        return args.roots.find((root) => AutonomyPostflightAuditService.isInsideRoot(root, args.path));
    }
    static isInsideRoot(root, target) {
        const relativeTarget = relative(root, target);
        return relativeTarget === '' || (!relativeTarget.startsWith('..') && !isAbsolute(relativeTarget));
    }
    static detectGitHistoryChange(command) {
        if (!command) {
            return false;
        }
        const normalized = command.trim().toLowerCase().replace(/\s+/g, ' ');
        return [
            /(?:^|[;&|])\s*git\s+commit\b/,
            /(?:^|[;&|])\s*git\s+reset\b/,
            /(?:^|[;&|])\s*git\s+rebase\b/,
            /(?:^|[;&|])\s*git\s+push\b.*\s--force(?:\s|$)/,
        ].some((pattern) => pattern.test(normalized));
    }
    static formatReason(args) {
        if (args.exceededDeclaredRoots.length > 0) {
            return `observed changes exceeded declared write roots: ${args.exceededDeclaredRoots.join(', ')}`;
        }
        if (args.gitHistoryChanged) {
            return 'observed git history mutation from command text';
        }
        if (args.changedPaths.length === 0) {
            return 'tool result did not report structured changed paths';
        }
        return args.decision === 'continue'
            ? 'observed changes stayed within declared write roots'
            : 'postflight audit requested stop';
    }
    static stringValue(value) {
        return typeof value === 'string' && value.trim().length > 0 ? value : undefined;
    }
    static stringArray(value) {
        return Array.isArray(value)
            ? value.filter((item) => typeof item === 'string' && item.trim().length > 0)
            : [];
    }
}
function isRecord(value) {
    return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
}
//# sourceMappingURL=postflight-audit-service.js.map