"use strict";
// SPDX-License-Identifier: AGPL-3.0-or-later
// Copyright (C) 2024-2026 Gracker (Chris)
// This file is part of SmartPerfetto. See LICENSE for details.
Object.defineProperty(exports, "__esModule", { value: true });
exports.createMemoryRoutes = createMemoryRoutes;
/**
 * Memory Routes — admin / inspection surface for the Plan 44
 * project + world memory store.
 *
 * Endpoints (all under `/api/memory`):
 *   GET    /                   list project + world entries
 *   GET    /audit              read-only promotion audit log
 *   POST   /promote            advance an entry across scopes
 *                              (the `consolidate_to_world_memory`
 *                              admin function from §4.5 lives here)
 *   DELETE /:entryId           remove an entry
 *
 * Notes:
 * - Recall is NOT exposed here — agents use the
 *   `recall_project_memory` MCP tool instead. This route is for
 *   operator-side inspection and promotion only.
 * - `POST /promote` enforces all `projectMemory.promoteEntry`
 *   invariants (auto-promotion forbidden, world requires
 *   reviewer_approval + reviewer name, etc.) and surfaces them
 *   as 400 with a descriptive error.
 *
 * @module memoryRoutes
 */
const express_1 = require("express");
const auth_1 = require("../middleware/auth");
const projectMemory_1 = require("../agentv3/projectMemory");
const enterpriseAuditService_1 = require("../services/enterpriseAuditService");
const rbac_1 = require("../services/rbac");
const scopedKnowledgeStore_1 = require("../services/scopedKnowledgeStore");
const runtimePaths_1 = require("../runtimePaths");
const DEFAULT_STORAGE_PATH = (0, runtimePaths_1.backendLogPath)('analysis_project_memory.json');
let cachedMemory = null;
function getDefaultMemory() {
    if (!cachedMemory)
        cachedMemory = new projectMemory_1.ProjectMemory(DEFAULT_STORAGE_PATH);
    return cachedMemory;
}
/** Test/factory hook — pass an explicit ProjectMemory, otherwise use
 * the default singleton. */
function createMemoryRoutes(memory) {
    const m = memory ?? getDefaultMemory();
    const router = (0, express_1.Router)();
    router.use(auth_1.authenticate);
    router.use((req, res, next) => {
        const context = (0, auth_1.requireRequestContext)(req);
        if (!(0, rbac_1.hasRbacPermission)(context, 'audit:read')) {
            (0, rbac_1.sendForbidden)(res, 'Memory administration requires audit:read permission');
            return;
        }
        next();
    });
    /**
     * GET /api/memory
     *
     * Query: optional `?scope=project|world`, `?projectKey=`, `?tag=`.
     * Lists entries deterministically; returns the count alongside.
     */
    router.get('/', (req, res) => {
        const storageScope = (0, scopedKnowledgeStore_1.knowledgeScopeFromRequestContext)((0, auth_1.requireRequestContext)(req));
        const { scope, projectKey, tag } = req.query;
        const filterScope = scope === 'project' || scope === 'world' ? scope : undefined;
        const entries = m.listProjectMemoryEntries({
            scope: filterScope,
            projectKey,
            anyOfTags: tag ? [tag] : undefined,
        }, storageScope);
        res.json({ success: true, entries, count: entries.length });
    });
    /**
     * GET /api/memory/audit
     *
     * Read-only view of the promotion audit log. Survives entry
     * removal so the reviewer trail stays permanent.
     */
    router.get('/audit', (_req, res) => {
        (0, auth_1.requireRequestContext)(_req);
        const audit = m.getPromotionAudit();
        res.json({ success: true, audit, count: audit.length });
    });
    /**
     * POST /api/memory/promote
     *
     * Body: `{entryId, policy: MemoryPromotionPolicy}`. The policy must
     * carry a `trigger` from the canonical enum
     * (user_feedback / reviewer_approval / skill_eval_pass);
     * auto_inferred is rejected.
     *
     * This is the operator-side `consolidate_to_world_memory` admin
     * surface from §4.5. Not exposed to the agent.
     */
    router.post('/promote', (req, res) => {
        const storageScope = (0, scopedKnowledgeStore_1.knowledgeScopeFromRequestContext)((0, auth_1.requireRequestContext)(req));
        const { entryId, policy } = (req.body ?? {});
        if (!entryId || !policy) {
            return res.status(400).json({
                success: false,
                error: '`entryId` and `policy` are required',
            });
        }
        try {
            m.promoteEntry(entryId, policy, storageScope);
            const entry = m.getProjectMemoryEntry(entryId, storageScope);
            (0, enterpriseAuditService_1.recordEnterpriseAuditEventForContext)((0, auth_1.requireRequestContext)(req), {
                action: 'memory.promoted',
                resourceType: 'memory',
                resourceId: entryId,
                metadata: {
                    fromScope: policy.fromScope,
                    toScope: policy.toScope,
                    trigger: policy.trigger,
                    reviewer: policy.reviewer,
                },
            });
            return res.status(200).json({ success: true, entry });
        }
        catch (err) {
            return res.status(400).json({
                success: false,
                error: err instanceof Error ? err.message : String(err),
            });
        }
    });
    /** DELETE /api/memory/:entryId */
    router.delete('/:entryId', (req, res) => {
        const storageScope = (0, scopedKnowledgeStore_1.knowledgeScopeFromRequestContext)((0, auth_1.requireRequestContext)(req));
        const removed = m.removeProjectMemoryEntry(req.params.entryId, storageScope);
        if (!removed) {
            return res.status(404).json({
                success: false,
                error: `Entry '${req.params.entryId}' not found`,
            });
        }
        (0, enterpriseAuditService_1.recordEnterpriseAuditEventForContext)((0, auth_1.requireRequestContext)(req), {
            action: 'memory.deleted',
            resourceType: 'memory',
            resourceId: req.params.entryId,
        });
        res.json({ success: true });
    });
    return router;
}
const memoryRoutes = createMemoryRoutes();
exports.default = memoryRoutes;
//# sourceMappingURL=memoryRoutes.js.map