import { CrtrClient } from '../api/index.js'; import type { CanvasSource } from '../core/canvas/source.js'; import type { NodeMeta, NodeRow, NodeStatus, SubscriptionRef } from '../core/canvas/types.js'; import type { Scope } from '../types.js'; import type { NodeDetailDTO } from '../api/dto/nodes.js'; /** Rethrow an `ApiError` as the clean structured CLI error agents parse * (`core/io` `handle`) — instead of the generic "internal bug" stderr path a * raw non-`CrtrError` throw would take. The mapping itself lives in ONE place * (`apiErrorToCliError`, `core/io.ts`); this is the explicit-catch helper a * leaf uses when it wants to attach a call-site `next` hint. Non-`ApiError` * throws propagate unchanged (a genuine bug still reads as `internal`). Typed * `never` so callers can use it as the tail of a `catch` without confusing * definite assignment. */ export declare function rethrowAsCliError(err: unknown, next?: string): never; /** Fetch a node, mapping ONLY a 404 to `null` (the "not found" contract every * existence-check leaf wants) and surfacing every other failure as the clean * network-class CLI error via `rethrowAsCliError`. This replaces the old * `.catch(() => null)` idiom that, post-B-1 (`getNode` is now an HTTP round-trip), * masked a broken/slow/restarting daemon as a false "node not found". Same * 404-only→null mapping as `ApiCanvasSource.orNull`, but returning the raw DTO * and rethrowing non-404s as CLI errors rather than swallowing them. */ export declare function getNodeOrNull(nodeId: string): Promise; /** Bounded tail of crtrd.err surfaced on a cold-start `/healthz` timeout * (issue #516). Large enough to catch a real startup failure/stack trace, * small enough that a runaway daemon log can never leak unbounded into a CLI * error message. */ export declare const COLD_START_DIAGNOSTIC_TAIL_BYTES = 4096; /** Read a bounded tail of crtrd's stderr log to enrich a `daemon_unavailable` * cold-start timeout (issue #516: the prior bare message discarded the actual * startup failure). Bounds the I/O itself — opens the file and reads only the * final `COLD_START_DIAGNOSTIC_TAIL_BYTES` bytes via `fstatSync`+`readSync`, * never `readFileSync`-ing the whole append-only log — then decodes/filters * that bounded slice. Best-effort and synchronous per the `coldStartDiagnostic` * contract — a missing/unreadable/empty log yields `undefined` so the base * message is used unchanged. */ export declare function readColdStartDiagnostic(): string | undefined; /** The local-socket `CrtrClient` every CLI verb uses. Autostart is on by * default: on a cold socket the injected `onColdSocket` hook fires * `ensureDaemon()` (spawns crtrd detached via the branded host), then the * client polls `/healthz` to a bounded deadline and retries once (the poll * lives inside `CrtrClient`, A-2). If crtrd never becomes reachable — or * autostart is disabled — the client throws `daemon_unavailable` (spec §7.1, * §8). This is the ONLY CLI reference to `ensureDaemon`. * * #508 follow-up: `onColdSocket` is fire-and-forget — `ensureDaemon()` spawns * crtrd and returns immediately, so the client's OWN `/healthz` poll is the * only deadline the initiating CLI invocation actually waits on. That poll * used to default to a fixed 10s window while `spawnDaemon`'s * `verifyDaemonStartup` (which `ensureDaemon`'s spawn transitively awaits, in * the detached child, on the SAME cold-start path) was widened to 20s for a * slow-but-valid cold boot: a daemon that took 12s was a valid, verified * startup, but the CLI process that triggered it still gave up and reported * `daemon_unavailable` at 10s. Passing the SAME `DAEMON_VERIFY_WINDOW_MS` * here keeps the two in lockstep — one authoritative window, not two that can * drift apart — without adding any retry/fallback poll loop. */ export declare function cliClient(opts?: { timeoutMs?: number; }): CrtrClient; export declare class ApiCanvasSource implements CanvasSource { private readonly client; private rosterCache; private rosterInFlight; constructor(client?: CrtrClient); private roster; /** Map a 404 from the API to the interface's `null` "not found" contract; * re-throw everything else. */ private orNull; getNode(nodeId: string): Promise; getRow(nodeId: string): Promise; listNodes(filter?: { status?: NodeStatus | NodeStatus[]; }): Promise; subscriptionsOf(subscriber: string): Promise; subscribersOf(publisher: string): Promise; /** BFS over the active `subscribes_to` edges from `root` (its transitive view), * excluding `root` itself — the same traversal shape as * `RemoteCanvasSource.view`, expressed over the API's edge lists. */ view(root: string): Promise; /** Per-NODE open-ticket counts across `root`'s view. The renderer badges each * node with the tickets it raised (the human bridge's parent), so this must * be per-node. Request only this view's ids: using the * enriched full-canvas snapshot for a five-second viewer poll blocked crtrd * behind metadata and telemetry reads for every historical node. */ ticketCountsForView(root: string): Promise>; /** True when `nodeId` has at least one active (`active` edge flag, not just a * live subscriber) subscription to a node that is currently live * (`active`/`idle` status). `subscriptionsOf`'s roster-backed edges carry the * real per-edge `active` flag, so this filter is exact, not an over-report. */ hasActiveLiveSubscription(nodeId: string): Promise; } /** The active read source for a CLI command. Mirrors `resolveCanvasSource`'s * selection WITHOUT importing `core/canvas/source.ts` (which pulls * `LocalCanvasSource` → `openDb`, failing the Stage-C import checker): an * explicit `--canvas ` wins, else the durable `crtr canvas use` selection * (`ScopeState.activeCanvas`), else the API-backed local source. The remote * branch reuses the verified-openDb-free `RemoteCanvasSource` (plan Q-3). */ export declare function cliCanvasSource(opts?: { canvasName?: string; scope?: Scope; }): CanvasSource;