/** * @license * Copyright 2026 Qwen * SPDX-License-Identifier: Apache-2.0 */ import type { PermissionDetails, PermissionOption } from './types.js'; export type PermissionOptionKind = PermissionOption['kind']; export declare const MAX_SUMMARY_CHARS = 4000; export declare const MAX_DETAIL_CHARS = 48000; export declare function isRecord(value: unknown): value is Record; /** * Map one wire permission option to the adaptor's kind + escalation. * * Both qwen serve and ACP stamp every option with the structured `kind` * (`allow_once` | `allow_always` | `reject_once` | `reject_always` — see * `toPermissionOptions` in packages/cli acp-integration/permissionUtils.ts); * that is authoritative when present. An unknown structured kind fails * closed to 'other'. The word heuristics run only when the backend omitted * the field entirely. */ export declare function classifyOption(optionId: string, name: string | undefined, wireKind: string | undefined): { kind: PermissionOptionKind; escalation?: 'once' | 'always'; }; /** Preserve the backend's declared scope, never invent one from an option id. */ export declare function describePersistentScope(name: string | undefined, wireKind: string | undefined): string | undefined; /** * The narrowest option of the wanted kind. A bare voice "allow" must take * the one-shot grant, never persist an always-allow rule (serve offers * [proceed_always_project, proceed_always_user, proceed_once, cancel] — * first-match would pick the project-wide rule). */ export declare function pickLeastEscalating(options: readonly PermissionOption[], wanted: PermissionOptionKind): PermissionOption | undefined; /** * The broadest persistent grant of the wanted kind, or undefined when the * backend offered none. * * Only a deliberate "allow always" reaches this. Agents advertise the * always-options narrowest first (qwen-code offers * [ProceedAlwaysProject, ProceedAlwaysUser, ...] for exec, so project * scope precedes machine-wide user scope), and ACP gives no other signal * to rank two `allow_always` entries by, so offer order is the tiebreak * and the FIRST match wins. An agent that omits always-options entirely * (qwen-code hides them under `forceHideAlwaysAllow`) yields undefined and * the caller must fall back to a one-shot grant rather than cancel. */ export declare function pickPersistentGrant(options: readonly PermissionOption[], wanted: PermissionOptionKind): PermissionOption | undefined; /** * Compose display-only permission text. Control sequences and credentials * must not reach the UI or spoken ask. Authority is based on separate * structured facts, never this sanitized title. */ export declare function describeToolCall(toolCall: unknown): string; /** Redact credential syntax, without normalizing the other command bytes. */ export declare function redactPermissionText(text: string): string; /** * Bounded untrusted operation facts, kept separately from the display title. * Whitespace/quoting is significant: exact-action matching must never use a * sanitized title. Redaction or loss of input is explicitly marked incomplete. */ export declare function describePermissionDetails(toolCall: unknown, sessionCwd?: string): PermissionDetails; /** * Remove terminal control sequences without the first-line cut that * sanitizeTitleLine applies, so multi-line display text stays readable. * Mirrors the same sequence families (OSC, CSI, SS2/SS3/DCS, C0/DEL/C1). */ export declare function stripControlSequences(text: string): string; /** * Slice the last `max` UTF-16 units, snapping the cut off a split surrogate * pair: a cut landing between the halves would lead with a lone low * surrogate that renders/speaks as U+FFFD. */ export declare function tailSlice(text: string, max: number): string; export declare function clampTail(text: string, max: number): string; /** * One clean line for a tool-call title: first line only, terminal control * sequences stripped. Minimal inline of core's stripTerminalControlSequences * (packages/core utils/terminalSafe.ts) — the monolith's voice consumer * applied the same guard before titles reached the realtime model * (live-session-coordinator.ts), and neither acp-bridge nor the daemon * sanitizes upstream. */ export declare function sanitizeTitleLine(title: string): string;