/**
 * `agents projects` — named, multi-repo projects and the progress
 * rollup. Definitions live in `~/.agents/projects/<name>.yaml` (see
 * `lib/projects.ts`); this registers the command tree over them.
 *
 * The headline is `status`: instead of the vague per-agent activity line, it
 * rolls every session up by project (matched on cwd) into one card — agents by
 * lifecycle state, plan completion, open PRs, and tickets in flight.
 */
import type { Command } from 'commander';
import { type ProjectDef, type ProjectRepo } from '../lib/projects.js';
import { type LinearMilestone } from '../lib/linear-project-counts.js';
/** Recursion guard: a peer answering a probe fan-out never re-fans-out itself. */
export declare const PROJECTS_NO_FANOUT_ENV = "AGENTS_PROJECTS_LOCAL";
/**
 * A path-shaped `agents projects view` argument — `.`, `..`, a `~`-prefixed
 * value, or anything containing a path separator — means "auto-detect the
 * project for this DIRECTORY", not "a project named literally this". A bare
 * token (no separators) stays a project name, exactly as before.
 */
export declare function looksLikePath(token: string): boolean;
/** Machine-readable shape of `agents projects view <path> --json`. */
export interface ViewDetection {
    /** Detected project name, or null when no definition contains the path. */
    name: string | null;
    /** The detected project's Linear binding; fields are null when unbound. */
    linear: {
        name: string | null;
        projectId: string | null;
    };
    /** The detected project's repo/monorepo root (home-relative), or null. */
    root: string | null;
}
/**
 * Best-effort cwd->project detection for `agents projects view <path>`. Delegates
 * to the shared {@link projectNameForCwd} (def-root containment, longest wins),
 * then reads the matched definition's Linear binding and root so ONE call yields
 * the name AND the Linear projectId. Fail-open: an all-null shape when nothing
 * contains the path — never throws, so a scripted caller stays unscoped rather
 * than crashing. This subsumes the removed `agents projects for-cwd`.
 */
export declare function detectProjectForPath(cwd: string, defs: ProjectDef[]): ViewDetection;
/**
 * One compact trailing note for peers that didn't answer the `--fleet`
 * fan-out — unreachable, running an agents-cli too old to carry `projects
 * probe`, or too slow to finish inside the 12s SSH budget. Mirrors
 * `formatUnreachableNote` (activity) with the probe-specific reasons; empty
 * string when everything answered.
 */
export declare function formatFleetSkippedNote(skipped: string[]): string;
/**
 * One compact trailing note for peers that DID answer a fan-out but whose
 * payload failed verification — a wrong machine id, a fingerprint that doesn't
 * match the targets we sent, or a malformed row. Deliberately separate from
 * {@link formatFleetSkippedNote}: silence means a peer never ran, while this
 * means it ran and we cannot trust what it reports, which is the worse state.
 * Empty string when every answer verified.
 */
export declare function formatFleetUnverifiedNote(unverified: string[]): string;
/**
 * Best-effort `owner/repo` from a repo's origin remote.
 *
 * `stderr: 'ignore'` is load-bearing, not tidiness. A checkout with no origin
 * makes git print `error: No such remote 'origin'` on ITS stderr, which is the
 * terminal's — the catch below never sees it. Absence of a remote is an
 * expected answer here (`undefined`), not something to report.
 */
export declare function originSlug(cwd: string): string | undefined;
/**
 * Turn a `--dir` / `--add-dir` value into a `repos[]` row.
 *
 * The slug comes from the DIRECTORY'S OWN origin remote, never from its path:
 * a checkout at `~/src/github.com/muqsitnawaz/agents-cli` whose origin is
 * `phnx-labs/agents-cli` must record the remote it actually pushes to. Pass
 * `slugOverride` for a directory with no origin (a vendored tree, a fresh
 * `git init`).
 *
 * The stored `path` is left for `writeProjectDef` to normalize home-relative,
 * so the same definition re-roots on every machine.
 */
export declare function projectRepoFromDir(dir: string, slugOverride?: string): {
    ok: true;
    repo: ProjectRepo;
} | {
    ok: false;
    error: string;
};
/** One `projects list` row, pre-render. */
export interface ProjectListRow {
    name: string;
    path: string;
    repo: string;
}
/**
 * Column widths for `projects list`, sized to the rows actually being printed.
 * Fixed padding was the bug: home-relative roots run past 50 characters, so a
 * hardcoded 32 pushed the repo column off its gridline on every long path.
 * Paths longer than {@link LIST_PATH_MAX} truncate rather than widen the table.
 */
export declare function computeProjectListWidths(rows: ProjectListRow[]): {
    name: number;
    path: number;
    repo: number;
};
/**
 * A milestone's target date as a person would say it — "due tomorrow",
 * "overdue by 3 days", "due Aug 21" — never a raw `2026-08-21` or a duration in
 * hours. Linear stores a calendar date with no timezone, so both sides are
 * compared at LOCAL midnight; parsing `YYYY-MM-DD` with `new Date(str)` would
 * read it as UTC and shift the answer by a day for anyone west of Greenwich.
 */
export declare function formatMilestoneDue(targetDate: string, nowMs: number): string | undefined;
/**
 * The milestone block. `status` prints one line — the next checkpoint — because
 * a roll-up across projects has to stay scannable. `view` prints every declared
 * milestone, because "how many are there and when are they due" is the shape of
 * the plan and the reason to open one project.
 *
 * Pure (chalk only) so the layout is testable without a Linear account.
 */
export declare function formatMilestoneLines(milestones: LinearMilestone[], next: LinearMilestone | undefined, nowMs: number, limit: number): string[];
/** The `next` card line: what this project is due to hit, and how far along it is. */
export declare function formatNextMilestone(ms: LinearMilestone, nowMs: number): string;
/** Options shared by `status` and `view`. */
export type ProjectCardOpts = {
    json?: boolean;
    window?: string;
    remote?: boolean;
    /** Scope the fleet fan-out to specific devices; undefined = the whole fleet. */
    deviceFilter?: string[];
};
/**
 * Merge `--device a b` (variadic) and `--devices a,b,c` (comma list) into one
 * deduped device filter; undefined when neither was given (= whole fleet).
 */
export declare function resolveDeviceFilter(device?: string[], devices?: string): string[] | undefined;
/** Print the YAML-side fields that sit under the shared card in `view` mode. */
export declare function printProjectDefinition(def: ProjectDef, name: string): void;
export declare function registerProjectsCommands(program: Command): void;
