import type { TspTone } from "@oh-my-pi/pi-wire"; /** How a field's values reduce to one number. */ export type JobWidgetAgg = "last" | "first" | "min" | "max" | "mean" | "sum" | "count" | "rate" | "delta" | "change"; export declare const JOB_WIDGET_AGGS: readonly JobWidgetAgg[]; export declare const JOB_WIDGET_TONES: readonly TspTone[]; /** * One line-matching rule. Every named group but `key` feeds the field of the * same name (`/^[a-z][a-z0-9_]{0,23}$/`) with its capture: a number, or text * for the `text` group (and for a capture that holds no number). Several * rules may feed one field. */ export interface JobWidgetRule { /** * Source id (`out`, `pipe:1`, `tools`, `bg_7:pipe:1`), `*` for all, a trailing `*` for a prefix * (`pipe:*`). Wildcards never cover `tools`; see {@link ruleReadsSource}. */ from: string; /** Rust-regex syntax with named groups, matched per line. */ match: string; /** Group splitting every field of the rule into one series per key; not a field itself. */ key?: string; /** Group whose capture is kept as text (the key's latest text), not parsed as a number. */ text?: string; /** Field counting the rule's matches. */ count?: string; /** Multiplies every number the rule captures. */ scale?: number; } /** A field one rule feeds; see {@link ruleFields}. */ export interface JobWidgetRuleField { field: string; /** The capture is kept as text, never parsed as a number. */ text: boolean; /** The rule's `count`: fed by the match itself, not a capture. */ count: boolean; } export type JobWidgetBetter = "higher" | "lower"; /** A number derived from one field. */ export interface JobWidgetValueRef { field: string; key?: string; agg: JobWidgetAgg; unit?: string; digits?: number; better?: JobWidgetBetter; } export interface JobWidgetSparkSpec { kind: "spark"; field: string; key?: string; label: string; unit?: string; better?: JobWidgetBetter; target?: number; targetLabel?: string; min?: number; max?: number; } export interface JobWidgetBarsSpec { kind: "bars"; field: string; agg: JobWidgetAgg; label: string; unit?: string; max?: number; better?: JobWidgetBetter; } export interface JobWidgetMeterSpec { kind: "meter"; field: string; agg: JobWidgetAgg; key?: string; total: number | JobWidgetValueRef; label: string; unit?: string; } export interface JobWidgetStatSpec { kind: "stat"; items: (JobWidgetValueRef & { label: string; })[]; } export interface JobWidgetGridSpec { kind: "grid"; field: string; label: string; /** Tone by the key's latest text: case-insensitive substring, first listed wins. */ tones: Record; } export interface JobWidgetTextSpec { kind: "text"; field: string; } export type JobWidgetBlockSpec = JobWidgetSparkSpec | JobWidgetBarsSpec | JobWidgetMeterSpec | JobWidgetStatSpec | JobWidgetGridSpec | JobWidgetTextSpec; export interface JobWidgetSpec { /** What is watched, ≤ 48 chars. */ title: string; /** 1–12. */ rules: JobWidgetRule[]; /** 1–4; the first is the primary block compact views show. */ blocks: JobWidgetBlockSpec[]; headline?: JobWidgetValueRef & { label?: string; }; /** Field whose latest captured text is the stage line. */ stage?: string; } export declare const MAX_TITLE_CHARS = 48; export declare const MAX_RULES = 12; export declare const MAX_BLOCKS = 4; export declare const MAX_STAT_ITEMS = 4; /** * JSON schema of {@link JobWidgetSpec}, carried by the forced `respond` tool * the author model calls. Deliberately bare (shapes and enums, no prose): the * system prompt documents every property, and the schema is billed as input * on every request. Semantic checks live in {@link validateJobWidgetSpec}. * Nothing is required at the top: a `skip` answer declines to draw a widget * ({@link jobWidgetSkip}); every other answer must carry `title`, `rules` * and `blocks`, which validation enforces. */ export declare const JOB_WIDGET_SPEC_SCHEMA: Record; /** Lines the author saw for one source, for the validation dry run. */ export interface JobWidgetSampleLines { id: string; lines: readonly string[]; } export type JobWidgetSpecValidation = { ok: true; spec: JobWidgetSpec; } | { ok: false; errors: string[]; }; /** * Why an authored answer declines to draw a widget (its `skip`), or * `undefined` for an answer offering a spec: nothing in the job's output is * a quantity worth watching. */ export declare function jobWidgetSkip(value: unknown): string | undefined; /** * Whether a rule's `from` names the source `id`. A subagent's `tools` (file * contents, search hits and command output mixed) is read only by a rule * naming it: a wildcard written for a command's output must not reach it. */ export declare function ruleReadsSource(from: string, id: string): boolean; /** Named groups a Rust pattern declares, in pattern order. */ export declare function patternGroupNames(pattern: string): Set; /** The fields a rule feeds: one per named group but `key`, then its `count`. */ export declare function ruleFields(rule: JobWidgetRule): JobWidgetRuleField[]; /** Whether an aggregation needs numbers (everything but match counting). */ export declare function aggNeedsValue(agg: JobWidgetAgg): boolean; /** * A captured number: `,`/`_` separators dropped, a `k`/`K`/`M`/`G` suffix * right after the digits multiplies; `NaN` when the text starts with no number. */ export declare function parseWidgetValue(text: string): number; /** * Parse and check an authored spec. `samples` (the lines the author saw) * enable the dry run, which rejects: * - rules matching none of the non-empty samples (an empty widget); * - a field read as a number whose sample captures hold none; * - rules reading omp's {@link TOOL_CALL_MARK} lines of a subagent's tool * calls (counting or naming tool calls is activity, not progress). * * With `brief` (the job's command, task and hints) as well, a constant meter * `total` or spark `target` must be a number the brief or the samples state: * an invented total draws a made-up fraction. A meter may use 100 without a * stated denominator when every numeric feeding rule supplies an observed, * unscaled percentage. */ export declare function validateJobWidgetSpec(value: unknown, samples?: readonly JobWidgetSampleLines[], brief?: string): JobWidgetSpecValidation;