/** * Plan dock, todo lists, /find, prompt-injection cards, and compact errors. */ import { type Theme } from './theme.js'; import { type TextSegment } from './term-text.js'; import type { AskUserQuestionItem } from '@deepseek-ai/dsh-user-questions'; import type { DiffDisplayLine, DisplayKind, PlanTodoItem, Row, SubagentLogEntry } from './transcript-types.js'; export declare const MAX_SUBAGENT_LOGS = 80; export declare const TODO_STATUS_MARK: Record; /** True while a plan still belongs in the dock (latest incomplete work). */ export declare function planIsLive(plan: { active: boolean; pending: boolean; todos: readonly PlanTodoItem[]; planMarkdown?: string; archived?: boolean; }): boolean; /** Open todos left behind when a turn ends without a completing todo_write. */ export declare function planTurnLeftOpen(plan: { todos: readonly PlanTodoItem[]; }): boolean; /** Mark leftover in-progress/pending todos as display-stale after turn/end. */ export declare function applyTurnEndToPlan(plan: T): T; /** Follow-up that asks the model to close leftover todos. One per open list. */ export declare function planCloseNudgeText(plan: { todos: readonly PlanTodoItem[]; }): string; export type CardCategory = 'thinking' | 'plan' | 'subagent' | 'reply' | 'tool' | 'question' | 'goal' | 'prompt'; /** Category for jump / search. Assistant replies are not collapsible cards. */ export declare function cardCategoryOf(row: { kind: string; }): CardCategory | undefined; export declare function cardCategoryLabel(category: CardCategory): string; export declare function parseCardCategoryToken(token: string): CardCategory | undefined; /** Split `/find thinking padAnsi` into an optional category and a query. */ export declare function parseFindQuery(raw: string): { category?: CardCategory; query: string; }; /** Classify one injected prompt blob into display sources. */ export declare function promptInjectionSources(text: string, plugin?: string): string[]; export declare function promptInjectionTitle(sources: readonly string[]): string; export declare function isPromptInjectionMessage(sourceKind: string, text: string, plugin?: string): boolean; /** Official `/compact` idle-only failures, mapped to a local sentence. */ export declare function formatCompactCommandError(text: string): string; export declare function compactionHeaderText(row: { status: 'running' | 'ok' | 'error'; pruneCount: number; prunedTokens: number; error?: string; }): string; /** Transcript rows matching a `/find` query, newest last. */ export declare function matchTranscriptRows(rows: readonly Row[], raw: string): Row[]; /** One-line note under an expanded plan strip. */ export declare function planDockNote(plan: { active: boolean; pending: boolean; todos: readonly PlanTodoItem[]; planMarkdown?: string; turnLeftOpen?: boolean; }): string; /** Compact per-status counts matching the web plan strip. */ export declare function todoProgressLabel(todos: readonly PlanTodoItem[]): string; export declare function todoItemKind(status: PlanTodoItem['status']): DisplayKind; /** * A Braille bar for the plan's completion, in the same family as the context * ring: `⣿` filled, `⣀` empty, and the eight partial cells between them. * @param todos - the list as the model last wrote it. * @param cells - bar width in cells. */ export declare function todoProgressBar(todos: readonly PlanTodoItem[], cells?: number): string; export declare function planMarkdownFromArgs(value: unknown): string | undefined; /** First markdown heading of an exit_plan_mode plan body. */ export declare function planTitleFromMarkdown(markdown: string): string | undefined; /** Parse a todo_write payload into displayable plan items. */ export declare function parsePlanTodos(value: unknown): PlanTodoItem[]; /** Compact todo-list summary: done/total plus the first in-progress task. */ export declare function todoSummary(value: unknown): string; /** Compact ask_user_question summary from tool arguments. */ export declare function askSummary(value: unknown): string; /** * The questions one `ask_user_question` call recorded, for the durable fold. * * The Session's own reader (`questionsOf` in `@deepseek-ai/dsh-user-questions`) * validates against the tool's schema and returns nothing when it does not match. * This one only has to be faithful enough to draw a card from a log entry this * process did not witness, so it takes the fields it can use and drops the rest * rather than refusing the whole call. * @param value - the tool call's arguments, raw JSON or already parsed. * @returns the questions, or an empty list when the shape is unusable. */ export declare function askQuestions(value: unknown): readonly AskUserQuestionItem[]; /** First non-empty line, collapsed to a single scan line. */ export declare function firstDisplayLine(text: string): string; /** Collapse a child-session blob to one short chip/wait-card line. */ export declare function clipSubagentActivity(text: string, maxChars?: number): string; /** Running / ok / aborted / error → theme token for the status dot and word. */ export declare function subagentStateColor(status: Extract['status'], theme?: Theme): string; /** * Rebuild a subagent chip from the parent spawn tool call that survives in the * session log. Live `subagent/start` is not replayed, so resume would otherwise * show a generic tool card titled from the English description ("probe"). */ export declare function subagentRowFromSpawnTool(input: { callId: string; task: string; provider?: string; /** Model route for the child, when the caller knows it. */ modelProvider?: string; local?: boolean; status?: Extract['status']; startedAt?: number; endedAt?: number; output?: string; }): Extract; /** * Courtesy title: distilled role plus a directional beast. * * The beast comes from the child's own session id, never the parent call id a * replayed chip was built with: the same child must keep its symbol across a * `--resume`. */ export declare function subagentDisplayName(row: Extract): string; /** * Short activity for the collapsed chip and wait card: prefer the parent * task name, else a clipped last log line. Never the full child transcript. */ export declare function subagentChipSummary(row: Extract): string; /** Header + SGR spans: identity color, status dot/word, muted summary. */ export declare function buildSubagentHeader(input: { focused: boolean; title: string; status: Extract['status']; elapsedLabel: string; summary: string; spinner?: string; inspectHint?: string; /** Different provider from the parent: paint the title cyan, not violet. */ foreign?: boolean; /** Active palette; callers pass the session's theme so `mono` stays monochrome. */ theme?: Theme; }): { plain: string; segments: TextSegment[]; }; /** Map a folded child-session event onto an existing display role. */ export declare function subagentLogDisplayKind(entry: SubagentLogEntry, status: Extract['status']): DisplayKind; /** * Overlay body: session line, stop reason, then the clipped child log. * * The child's session id is the one `/subagents kill` takes, so it belongs on * this line — the collapsed chip stays free of opaque ids. */ export declare function subagentInspectLines(row: Extract): DiffDisplayLine[]; /** * Classify a child-session error so the chip can say *why* it died, not just * that it ended. Quota and expired auth get a command that actually helps; * everything else keeps a clipped diagnostic. */ export declare function describeSubagentFailure(input: { stopReason?: string; message?: string; provider?: string; }): { hint: string; kind: 'quota' | 'auth' | 'effort' | 'error'; } | undefined; export declare function appendSubagentLog(row: Extract, entry: SubagentLogEntry): void; /** Fold a child user/plugin blob: reminders become one inject chip, not raw XML. */ export declare function foldSubagentUserLog(row: Extract, text: string, sourceKind?: string, plugin?: string): void;