"use strict";
/**
 * Pure helpers for the shim-side read-warning probe.
 *
 * The upstream `mcp-neo4j-cypher@0.6.0` server runs the cypher against Neo4j
 * itself and returns rendered text; it drops `result.summary.notifications`
 * before serialising the JSON-RPC response. That is the dropped-envelope leg
 * of failure mode `676504f1`: the agent ran `RETURN h.hostname` against a
 * node whose property is `hostnameValue`, Neo4j emitted `gql_status=01N52
 * "property does not exist"`, the upstream surfaced it to its stderr but
 * NOT to the tool result, and the agent saw `[]` with no actionable signal.
 *
 * The shim now runs the same cypher in a second, lightweight pass against
 * its own Neo4j driver — only to read `summary.notifications` and stitch
 * codes matching `^0[12]N5\d$` into a warnings prefix block on the
 * upstream's response. The probe is sequential (after the upstream has
 * returned) so concurrent ordering and error-handling stay simple. The
 * upstream's rendered row text is left byte-for-byte untouched as
 * `content[1]`, so existing callers that read the rows do not see a format
 * change.
 *
 * Extracted from index.ts so the filter/stitch logic is testable as pure
 * functions without booting the shim's stdin/stdout pipe.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.filterEnvelopeNotifications = filterEnvelopeNotifications;
exports.stitchWarningsIntoResponse = stitchWarningsIntoResponse;
exports.runReadProbe = runReadProbe;
/** GQL status codes Neo4j 5.x emits for missing / unrecognised schema tokens.
 *  Covers 01N5x ("property does not exist", "type does not exist", etc.) and
 *  02N5x (label / type missing in pattern). These are the codes whose loss
 *  most often manifests as an empty-rows result the agent cannot diagnose. */
const ENVELOPE_GQL_RE = /^0[12]N5\d$/;
/** Keep only notifications whose gql_status matches the envelope-passthrough set. */
function filterEnvelopeNotifications(notifications) {
    const out = [];
    for (const n of notifications) {
        if (typeof n.gqlStatus === "string" && ENVELOPE_GQL_RE.test(n.gqlStatus)) {
            out.push({
                gql_status: n.gqlStatus,
                description: n.description,
                position: n.position ?? null,
            });
        }
    }
    return out;
}
/**
 * Prepend a warnings content block to a JSON-RPC read response.
 * Returns the rewritten JSON string, or `null` if there are no warnings to
 * surface (caller forwards the original line unchanged in that case).
 */
function stitchWarningsIntoResponse(msg, warnings) {
    if (warnings.length === 0)
        return null;
    const lines = warnings.map((w) => `  - gql_status=${w.gql_status} ${w.description}` +
        (w.position
            ? ` (line ${w.position.line}, column ${w.position.column})`
            : ""));
    const text = "Neo4j envelope warnings — these were emitted by the driver but " +
        "dropped by the upstream server. Treat them as schema feedback on " +
        "the cypher you just ran:\n" +
        lines.join("\n") +
        "\n\n--- results below ---";
    const original = msg.result?.content ?? [];
    const wrapped = {
        ...msg,
        result: {
            ...(msg.result ?? {}),
            content: [{ type: "text", text }, ...original],
        },
    };
    return JSON.stringify(wrapped);
}
/**
 * Run cypher through the shim's driver purely to capture
 * `result.summary.notifications`. The probe is best-effort: any error closes
 * the session and rethrows so the caller can decide to forward the
 * upstream's response unchanged.
 */
async function runReadProbe(driver, cypher, params) {
    const session = driver.session();
    try {
        const result = await session.run(cypher, params);
        return result.summary.notifications ?? [];
    }
    finally {
        await session.close().catch(() => {
            /* session already closed on error path — swallow */
        });
    }
}
//# sourceMappingURL=cypher-shim-read.js.map