/** * `/kanban` — Open the project kanban panel and perform common board/task * operations from the TUI composer. * * Subcommands (no subcommand → opens the kanban panel): * * /kanban — open the project kanban panel * /kanban create — create a new board, then open the panel * /kanban add <title> [--column X] [--desc <text>] — add a task to the active board (managed boards require --desc) * /kanban use <boardId|title|tag> — open the kanban panel on a specific board * /kanban boards — list every board in the project * /kanban health — show kanban queue health summary * /kanban audit [boardId|all] — show kanban cleaner audit (KanbanAuditSummary) * /kanban help — show usage * * The slash command intentionally mirrors the WebUI `kanban` surface so * users can perform the same operations in either surface. The TUI panel * remains the rich interactive view (navigate, move, assign); this command * is the text-first equivalent for when the panel is closed. */ import type { SlashCommand } from '@wrongstack/core/types'; import type { KanbanBoardSummary, KanbanBoundaryAccess, KanbanBoundaryPolicy, KanbanBoundarySelectorKind, KanbanQueueHealth } from '@wrongstack/kanban'; import { type KanbanAuditSummary } from './kanban-audit.js'; /** * Result of resolving the board that an `add` operation should target. * * `KanbanPanel` resolves the active board from the session tag * (`session:<sessionId>`) and falls back to the most-recently-updated board. * We mirror that exact precedence so a `/kanban add` issued while the panel * is open lands on the same board the user is looking at. */ export interface KanbanAddTarget { boardId: string; boardTitle: string; /** Column that the task will be placed in. Defaults to the first column. */ columnId: string; /** * Whether the board enforces the managed Kanban Agent lifecycle. Managed * boards require new cards to be created in the Backlog column and with a * description, so callers route the user accordingly. */ managed: boolean; } export interface KanbanSlashDeps { /** * Absolute project root used by the kanban file store. Must match the * value `KanbanPanel` reads from `agent.ctx.projectRoot` — using * `agent.ctx.cwd` would diverge when the user launches the TUI from a * subdirectory of the project. */ projectRoot: string; /** Optional session id; when present, prefer a `session:<id>`-tagged board. */ sessionId?: string | null | undefined; /** * Panel-open bridge installed by `App`. Calling `onPanelOpen.current(...)` * with `'toggleKanbanPanel'` opens the kanban panel — same mechanism the * other slash commands use. When absent, slash command returns text-only. */ onPanelOpen?: { current: ((action: string) => boolean) | null; } | undefined; /** * Optional hook that selects a specific board in the kanban panel. Used * by `/kanban use <boardId|title|tag>` and the Goal → Kanban bridge. * The callback receives a board id and returns true on success. */ onBoardFocus?: { current: ((boardId: string) => boolean) | null; } | undefined; /** Terminal width (cols) for help / boards table rendering. */ terminalWidth?: number | undefined; } export declare function createKanbanSlashCommand(deps: KanbanSlashDeps): SlashCommand; export type ParsedKanbanArgs = { kind: 'open'; } | { kind: 'help'; } | { kind: 'boards'; } | { kind: 'create'; title: string; } | { kind: 'add'; title: string; column: string | null; description?: string | undefined; } | { kind: 'use'; query: string; } | { kind: 'health'; } | { kind: 'audit'; boardQuery: string; } | { kind: 'boundary'; boardQuery: string; action: 'show' | 'allow' | 'deny' | 'clear'; taskQuery?: string | undefined; selectorKind?: KanbanBoundarySelectorKind | undefined; access?: KanbanBoundaryAccess | undefined; path?: string | undefined; enforcement?: KanbanBoundaryPolicy['enforcement'] | undefined; shellAccess?: KanbanBoundaryPolicy['shellAccess'] | undefined; }; /** * Parse the raw `args` string (everything after `/kanban`) into a tagged * union. Exported so tests can exercise the grammar in isolation. * * Grammar (whitespace-separated; quoted titles supported for the `create` * subcommand): * * args ::= ε | "help" | "boards" | "create" title * | "add" title ("--" "column" columnId)? * title ::= token+ * columnId ::= token */ export declare function parseKanbanArgs(raw: string): ParsedKanbanArgs; /** * Resolve the board that an `/kanban add` should target, matching the * precedence used by `KanbanPanel`: * * 1. The board tagged with `session:<sessionId>` (when a session id is known). * 2. The most-recently-updated board (sort by `updatedAt` desc). * * If `column` is given, prefer a column whose id or title matches. The match is * case-insensitive and falls back to the first column when nothing matches. * * Exported so tests can validate the precedence rules against fixture boards. */ export declare function resolveAddTarget(deps: Pick<KanbanSlashDeps, 'projectRoot' | 'sessionId'>, column: string | null): Promise<KanbanAddTarget | null>; /** * Resolve a user-supplied board query to a specific board. Three match * strategies are tried in order: * * 1. **Exact id match** — fastest, never ambiguous. * 2. **Exact title match** (case-insensitive) — what `/kanban use Sprint 2` * should hit when the user types the title verbatim. * 3. **Tag match** — for `goal:<text>` or `session:<id>` tags so the * Goal → Kanban bridge can navigate by tag without knowing the id. * * Returns null when no summary matches. The caller can then surface a * helpful error pointing at `/kanban boards`. */ export declare function resolveBoardByQuery(deps: Pick<KanbanSlashDeps, 'projectRoot'>, query: string): Promise<KanbanBoardSummary | null>; /** * Render the kanban queue health report as a compact markdown block. * Surfaces the same Sprint-2 fields the WebUI's `KanbanView` shows * (dependencyBlocked, staleAssignments, failedRetryable, heartbeatDue) * plus per-status counts and the last dispatch / last recovery stamps. */ export declare function renderHealthReport(health: KanbanQueueHealth): string; /** * Render the Kanban Cleaner audit across the project. Mirrors the WebUI * `KanbanCleanerAlert` vocabulary so a user running either surface gets * the same findings. * * Two modes: * - `boardQuery` empty → audit every board (per-board table). * - `boardQuery` present → audit the single matching board, or report * a clear "not found" error. * * Each board's row shows the issue counts (error · warning) and the * top-3 issues, biasing toward error severity first. */ export declare function renderProjectAudit(deps: Pick<KanbanSlashDeps, 'projectRoot'>, boardQuery: string): Promise<string>; /** * Render a board-row table from a list of audited boards. The output * is a compact markdown block suitable for the slash composer. * * When `multi` is true (audit-all mode) each row is prefixed with the * board title; in single-board mode the title appears once as a header. */ export declare function renderAuditReport(rows: ReadonlyArray<{ title: string; summary: KanbanAuditSummary; error?: string; }>, multi: boolean): string; /** * Render a compact boards table. Width-aware so a 60-col terminal still gets * useful output (column titles truncated, counts abbreviated). */ export declare function renderBoardsList(boards: readonly KanbanBoardSummary[], width?: number): string; //# sourceMappingURL=kanban-slash.d.ts.map