"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.
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.InvalidSessionIdError = void 0;
exports.resolveHome = resolveHome;
exports.computePaths = computePaths;
exports.ensureLayout = ensureLayout;
exports.assertValidSessionId = assertValidSessionId;
exports.sessionPaths = sessionPaths;
exports.ensureSessionLayout = ensureSessionLayout;
exports.scanSessionIds = scanSessionIds;
/**
 * Path resolution for the CLI's user-local storage.
 *
 * Layout:
 *   $SMARTPERFETTO_HOME/                (default: ~/.smartperfetto)
 *   ├── index.json                      (global session catalog)
 *   ├── traces/                         (CLI-managed trace copies)
 *   └── sessions/
 *       └── <sessionId>/
 *           ├── config.json
 *           ├── conclusion.md           (latest turn's conclusion)
 *           ├── transcript.jsonl
 *           ├── stream.jsonl            (raw StreamingUpdate log)
 *           ├── claim-support.json      (latest Evidence Contract claim support)
 *           ├── claim-verification.json (latest deterministic verifier result)
 *           ├── identity-resolutions.json
 *           ├── report.html             (latest HTML report)
 *           └── turns/NNN.md            (per-turn full answer)
 *
 * Override with `--session-dir` flag or `SMARTPERFETTO_HOME` env var.
 */
const fs = __importStar(require("fs"));
const os = __importStar(require("os"));
const path = __importStar(require("path"));
/** Resolve a home override from argv/env. Does NOT create directories — that's ensureLayout's job. */
function resolveHome(overrideDir) {
    if (overrideDir && overrideDir.trim())
        return path.resolve(overrideDir);
    const envHome = process.env.SMARTPERFETTO_HOME;
    if (envHome && envHome.trim())
        return path.resolve(envHome);
    return path.join(os.homedir(), '.smartperfetto');
}
/** Return the resolved layout without touching the filesystem. */
function computePaths(overrideDir) {
    const home = resolveHome(overrideDir);
    return {
        home,
        sessionsRoot: path.join(home, 'sessions'),
        tracesRoot: path.join(home, 'traces'),
        indexFile: path.join(home, 'index.json'),
    };
}
/** Create the home + sessions directories if missing. Idempotent. */
function ensureLayout(paths) {
    fs.mkdirSync(paths.sessionsRoot, { recursive: true });
    fs.mkdirSync(paths.tracesRoot, { recursive: true });
}
/**
 * Valid session id pattern: alphanumeric + hyphen only. The real ids we mint
 * ourselves look like `agent-<timestamp>-<random>` which satisfies this. We
 * reject anything else up-front so `sessionPaths` can't be coaxed into
 * traversing outside `sessionsRoot` via `../` or absolute-path inputs, which
 * would turn `rm` into an arbitrary-delete for any tree that happens to
 * contain a `config.json`.
 */
const SESSION_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_\-]{0,127}$/;
class InvalidSessionIdError extends Error {
    constructor(sessionId) {
        super(`invalid session id: ${JSON.stringify(sessionId)} (allowed: alphanumeric + "-_", 1-128 chars)`);
        this.name = 'InvalidSessionIdError';
    }
}
exports.InvalidSessionIdError = InvalidSessionIdError;
/** Throws InvalidSessionIdError on anything that doesn't match the pattern. */
function assertValidSessionId(sessionId) {
    if (typeof sessionId !== 'string' || !SESSION_ID_PATTERN.test(sessionId)) {
        throw new InvalidSessionIdError(sessionId);
    }
}
function sessionPaths(paths, sessionId) {
    assertValidSessionId(sessionId);
    const dir = path.join(paths.sessionsRoot, sessionId);
    // Defense-in-depth: even with the pattern guard above, verify the resolved
    // dir stays under sessionsRoot. Catches symlink games and future pattern
    // relaxations that might let path segments slip through.
    const resolvedRoot = path.resolve(paths.sessionsRoot);
    const resolvedDir = path.resolve(dir);
    if (resolvedDir !== path.join(resolvedRoot, sessionId) && !resolvedDir.startsWith(`${resolvedRoot}${path.sep}`)) {
        throw new InvalidSessionIdError(sessionId);
    }
    return {
        dir,
        config: path.join(dir, 'config.json'),
        conclusion: path.join(dir, 'conclusion.md'),
        transcript: path.join(dir, 'transcript.jsonl'),
        stream: path.join(dir, 'stream.jsonl'),
        claimSupport: path.join(dir, 'claim-support.json'),
        claimVerification: path.join(dir, 'claim-verification.json'),
        identityResolutions: path.join(dir, 'identity-resolutions.json'),
        report: path.join(dir, 'report.html'),
        turnsDir: path.join(dir, 'turns'),
    };
}
/** Create the per-session folder tree. Idempotent. */
function ensureSessionLayout(sp) {
    fs.mkdirSync(sp.dir, { recursive: true });
    fs.mkdirSync(sp.turnsDir, { recursive: true });
}
/** Return session directory name → sessionId mapping by scanning sessions/. */
function scanSessionIds(paths) {
    if (!fs.existsSync(paths.sessionsRoot))
        return [];
    return fs
        .readdirSync(paths.sessionsRoot, { withFileTypes: true })
        .filter((d) => d.isDirectory())
        .map((d) => d.name);
}
//# sourceMappingURL=paths.js.map