// Session-name resolution for the pi NATS channel adapter. // // Mirrors the OMP adapter's `extensions/session.ts`: composes the SDK's // `readSessionLabel` (canonical SESH_SESSION + `.sesh/` state-walk) with the // legacy `NATS_SESSION_NAME` operator override, per-context // `config.sessionName`, and a `basename(cwd)` last-resort fallback. // Centralised here so the resolution ladder is unit-testable without // spinning up the whole extension. import { basename } from "node:path"; import { readSessionLabel } from "@agent-ops/sesh-channels"; export interface SessionResolverInputs { env: NodeJS.ProcessEnv; configSessionName?: string; cwd: string; sanitize: (raw: string) => string; readSessionLabelImpl?: typeof readSessionLabel; } /** * Resolve the raw (pre-collision-check) session name. Returns the empty * string if no source yields a value — callers supply their own adapter * default. * * Resolution order (first non-empty wins): * 1. `readSessionLabel()` — SDK helper: `$SESH_SESSION` then `.sesh/` * state-walk. * 2. `$NATS_SESSION_NAME` — operator override (kept for back-compat). * 3. `config.sessionName` — legacy NATS-context-bound setting. * 4. `sanitize(basename(cwd))` — final fallback. */ export function resolveRawSession(inputs: SessionResolverInputs): string { const reader = inputs.readSessionLabelImpl ?? readSessionLabel; const fromSdk = reader({ env: inputs.env }); if (fromSdk && fromSdk.length > 0) return fromSdk; const fromOperator = inputs.env.NATS_SESSION_NAME; if (fromOperator && fromOperator.length > 0) return fromOperator; if (inputs.configSessionName && inputs.configSessionName.length > 0) { return inputs.configSessionName; } return inputs.sanitize(basename(inputs.cwd)); }