@mohamedatia/fly-design-system 2.13.0 → 2.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,6 +2,7 @@ import * as _angular_core from '@angular/core';
2
2
  import { Type, InjectionToken, Signal, WritableSignal, OnInit, EventEmitter, OnChanges, OnDestroy, SimpleChanges, PipeTransform, signal, AfterViewInit, ElementRef } from '@angular/core';
3
3
  import { Observable } from 'rxjs';
4
4
  import { ControlValueAccessor, Validator, AbstractControl, ValidationErrors } from '@angular/forms';
5
+ import { Editor } from '@tiptap/core';
5
6
  import { NavigationExtras } from '@angular/router';
6
7
  import * as _mohamedatia_fly_design_system from '@mohamedatia/fly-design-system';
7
8
 
@@ -123,6 +124,37 @@ declare const FLYOS_LAUNCH_EVENT = "flyos:launch";
123
124
  declare const FlyosPendingLaunchesGlobalKey: "__FLYOS_PENDING_LAUNCHES__";
124
125
  /** Type of the `globalThis[FlyosPendingLaunchesGlobalKey]` registry. */
125
126
  type FlyosPendingLaunches = Record<string, LaunchContext>;
127
+ /**
128
+ * Detail payload of the <c>flyos:remote-route</c> window CustomEvent — the
129
+ * INVERSE of {@link FLYOS_LAUNCH_EVENT}. A federated remote dispatches this
130
+ * whenever its OWN logical route changes (user navigation inside the remote), so
131
+ * the shell — the single owner of the browser address bar and history — can
132
+ * mirror the route to `…/desktop?app=&route=` and push one history entry.
133
+ *
134
+ * Emitted by `FlyRemoteRouter` ONLY when {@link FlyosShellOwnsHistoryGlobalKey}
135
+ * is set (a new shell is present and listening). Older shells receive no event
136
+ * and the remote keeps writing its own `pushState` — so this is backward
137
+ * compatible.
138
+ */
139
+ interface FlyRemoteRouteEventDetail {
140
+ /** The shell-registry app id (from `WINDOW_DATA`). */
141
+ readonly appId: string;
142
+ /** The window instance id, or null when `WINDOW_DATA` is split across bundles. */
143
+ readonly windowId: string | null;
144
+ /** The remote's new logical URL, e.g. `/signals/abc`. */
145
+ readonly url: string;
146
+ }
147
+ /** Name of the window CustomEvent a remote dispatches when its route changes. */
148
+ declare const FLYOS_REMOTE_ROUTE_EVENT = "flyos:remote-route";
149
+ /**
150
+ * `globalThis` flag set by the shell when it owns the address bar + history for
151
+ * ALL windows (os-core AND remotes) via `ShellHistoryService`. When set, a
152
+ * remote's `FlyRemoteRouter` defers history to the shell (dispatching
153
+ * {@link FLYOS_REMOTE_ROUTE_EVENT} instead of calling `history.pushState`) and
154
+ * stops handling its own `popstate` (the shell replays routes via
155
+ * {@link FLYOS_LAUNCH_EVENT}). Absent ⇒ legacy self-managed behaviour.
156
+ */
157
+ declare const FlyosShellOwnsHistoryGlobalKey: "__FLYOS_SHELL_OWNS_HISTORY__";
126
158
  /**
127
159
  * Hint published by an app to drive the window-titlebar help-button deeplink.
128
160
  *
@@ -860,8 +892,12 @@ interface LoadBundleOptions {
860
892
  /**
861
893
  * Shared I18nService for the shell and Business Apps.
862
894
  *
863
- * **Merge order** (later keys win): shell layer → remote bundles in registration order.
895
+ * **Merge order** (later keys win): DS baseline → shell layer → remote bundles
896
+ * in registration order.
864
897
  *
898
+ * - Baseline: {@link DS_BASELINE_LOCALES} — built-in strings for DS components
899
+ * (markdown editor, entity lookup) so they render localized labels even in a
900
+ * standalone consumer that never populated the shell layer. Always overridable.
865
901
  * - Shell: `setShellTranslations()` after loading `locale/{lang}.json` and API overrides.
866
902
  * - Remotes: `loadBundle()` per manifest `localeBaseUrl`.
867
903
  */
@@ -872,6 +908,9 @@ declare class I18nService {
872
908
  private readonly _bundleOrder;
873
909
  private readonly _locale;
874
910
  private readonly _version;
911
+ /** Built-in DS strings for the active locale (falls back to `en` for any
912
+ * locale we don't ship). Lowest-priority layer — always overridable. */
913
+ private readonly _baseline;
875
914
  private readonly _merged;
876
915
  readonly locale: _angular_core.Signal<string>;
877
916
  readonly version: _angular_core.Signal<number>;
@@ -893,6 +932,27 @@ declare class I18nService {
893
932
  static ɵprov: _angular_core.ɵɵInjectableDeclaration<I18nService>;
894
933
  }
895
934
 
935
+ /**
936
+ * Baseline UI strings for design-system components (markdown editor, entity
937
+ * lookup, …) in the four platform locales (`en`, `ar`, `fr`, `ur`).
938
+ *
939
+ * These are registered as the **lowest-priority** layer of {@link I18nService}
940
+ * (below the shell layer and any remote bundle), so DS components render real,
941
+ * localized labels even in a **standalone** consumer — a Business App running
942
+ * outside the desktop shell that never called `setShellTranslations()` — which
943
+ * would otherwise see raw keys (`common.label.bold`) as the pipe's fallback.
944
+ *
945
+ * Precedence: any consumer-supplied key with the same name still wins, so this
946
+ * is a safe default that an integrator can override without coordination.
947
+ *
948
+ * Scope: only the keys the **shippable** DS components reference today
949
+ * (`common.*` toolbar/link labels + `agent.lookup.*`). When a new DS component
950
+ * starts using `| translate`, add its keys here so it stays self-sufficient.
951
+ * Values are copied verbatim from the shell's `public/locale/*.json` — keep
952
+ * them in sync if either side changes.
953
+ */
954
+ declare const DS_BASELINE_LOCALES: Readonly<Record<string, Readonly<Record<string, string>>>>;
955
+
896
956
  /** Single source of truth for persisted / API theme strings. */
897
957
  declare const FLY_THEME_MODE_IDS: readonly ["light", "dark"];
898
958
  type FlyThemeMode = (typeof FLY_THEME_MODE_IDS)[number];
@@ -1144,6 +1204,14 @@ declare class FlyRemoteRouter {
1144
1204
  * (a known Native Federation edge case).
1145
1205
  */
1146
1206
  readonly isEmbedded: boolean;
1207
+ /**
1208
+ * True when a new shell owns the browser address bar + history for every
1209
+ * window (it set {@link FlyosShellOwnsHistoryGlobalKey}). In that mode this
1210
+ * router defers history to the shell: it dispatches {@link FLYOS_REMOTE_ROUTE_EVENT}
1211
+ * instead of `pushState`, and does not handle its own `popstate` (the shell
1212
+ * replays routes via `FLYOS_LAUNCH_EVENT`). Absent ⇒ legacy self-managed mode.
1213
+ */
1214
+ private get shellOwnsHistory();
1147
1215
  private readonly _url;
1148
1216
  /**
1149
1217
  * Current logical URL of the remote — `/signals/abc` etc.
@@ -1707,899 +1775,1154 @@ declare class MockAuthService {
1707
1775
  static ɵprov: _angular_core.ɵɵInjectableDeclaration<MockAuthService>;
1708
1776
  }
1709
1777
 
1710
- interface ContextMenuItem {
1711
- id: string;
1712
- label: string;
1713
- icon: string;
1714
- }
1715
- interface ContextMenuSection {
1716
- label?: string;
1717
- items: ContextMenuItem[];
1718
- }
1719
- declare class ContextMenuComponent implements AfterViewInit, OnDestroy {
1720
- private menuEl?;
1721
- private readonly doc;
1722
- private readonly hostEl;
1723
- x: _angular_core.InputSignal<number>;
1724
- y: _angular_core.InputSignal<number>;
1725
- sections: _angular_core.InputSignal<ContextMenuSection[]>;
1726
- action: _angular_core.OutputEmitterRef<string>;
1727
- closed: _angular_core.OutputEmitterRef<void>;
1728
- private menuWidth;
1729
- private menuHeight;
1730
- private previouslyFocused;
1731
- clampedPos: _angular_core.Signal<{
1732
- left: number;
1733
- top: number;
1734
- }>;
1735
- ngAfterViewInit(): void;
1736
- ngOnDestroy(): void;
1737
- onAction(id: string): void;
1738
- onClickOutside(event: MouseEvent): void;
1739
- onEscape(): void;
1740
- onContextMenu(event: MouseEvent): void;
1741
- onKeydown(event: KeyboardEvent): void;
1742
- private close;
1743
- private getMenuItems;
1744
- private focusItem;
1745
- private restoreFocus;
1746
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<ContextMenuComponent, never>;
1747
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<ContextMenuComponent, "fly-context-menu", never, { "x": { "alias": "x"; "required": true; "isSignal": true; }; "y": { "alias": "y"; "required": true; "isSignal": true; }; "sections": { "alias": "sections"; "required": true; "isSignal": true; }; }, { "action": "action"; "closed": "closed"; }, never, never, true, never>;
1748
- }
1749
-
1750
- declare enum MessageBoxButtons {
1751
- OK = 0,
1752
- OKCancel = 1,
1753
- YesNo = 2,
1754
- YesNoCancel = 3,
1755
- RetryCancel = 4,
1756
- AbortRetryIgnore = 5
1757
- }
1758
- declare enum MessageBoxIcon {
1759
- None = 0,
1760
- Information = 1,
1761
- Warning = 2,
1762
- Error = 3,
1763
- Question = 4
1764
- }
1765
- declare enum DialogResult {
1766
- None = 0,
1767
- OK = 1,
1768
- Cancel = 2,
1769
- Yes = 3,
1770
- No = 4,
1771
- Retry = 5,
1772
- Abort = 6,
1773
- Ignore = 7
1774
- }
1775
- interface MessageBoxOptions {
1776
- title: string;
1777
- message: string;
1778
- buttons?: MessageBoxButtons;
1779
- icon?: MessageBoxIcon;
1780
- }
1781
1778
  /**
1782
- * Configuration for the "Don't ask again" checkbox rendered by
1783
- * `showAcknowledged()`. The field is intentionally NOT part of the base
1784
- * `MessageBoxOptions` so the type system enforces the rule
1785
- * "checkbox caller MUST use `showAcknowledged()`": the classic `show()`
1786
- * entry point cannot accept this shape, eliminating the silent-discard
1787
- * dark-pattern path where the user's choice was thrown away.
1779
+ * Agent input contracts.
1780
+ *
1781
+ * These types define the wire and DI surface for the new `<fly-agent-input>` orchestrator
1782
+ * (Phase 2+). Phase 1 ships only the contracts: payload envelope, command/drop registry
1783
+ * shapes, and chip-host inputs. The concrete components consume them later.
1784
+ *
1785
+ * Design rules:
1786
+ * - All fields are `readonly` — the registries store these in signal stores and we never
1787
+ * want a host mutating after registration. Hosts construct fresh objects to update.
1788
+ * - The discriminated kinds (`scope`, `mode`, `kind`) carry the entire variance — no
1789
+ * boolean flags. New variants extend the union without breaking existing consumers.
1790
+ * - The `Type<AgentChipHostInputs<T>>` shape is intentional: chip components declare
1791
+ * `payload`, `mode`, optional `onRemove` as Angular `input()` signals; the registry
1792
+ * wires them via `NgComponentOutlet` inputs in the consumer. The component reference
1793
+ * itself never leaks across the federation boundary by value — only by class identity.
1788
1794
  */
1789
- interface MessageBoxDontAskAgainConfig {
1790
- /** i18n key for the checkbox label, e.g. 'agent.command.builtin.clear.dont_ask_again'. */
1791
- labelKey: string;
1792
- /** Initial checked state. Default false. */
1793
- defaultChecked?: boolean;
1795
+ /** Frozen MIME used by `flyAgentDraggable` and the drop-zone reader. Never change without a DS major. */
1796
+ declare const AGENT_DRAG_MIME: "application/x-fly-agent-payload+json";
1797
+ /**
1798
+ * Frozen payload envelope version.
1799
+ *
1800
+ * v1 — minimal drag payload: kind / appId / version / payload / plainTextFallback /
1801
+ * suggestedCommandIds. Still used by the drag/drop surface.
1802
+ *
1803
+ * v2 — bus envelope ({@link AgentMessageEnvelope}). Adds optional `userMessage`,
1804
+ * `systemContext`, `attachments`, `mcpScope` so a dispatcher can give the agent
1805
+ * rich context without polluting the user-visible message bubble. v2 is a
1806
+ * superset of v1 — every v1 payload is a valid v2 payload — so the version
1807
+ * number ratchets forward without breaking existing callers.
1808
+ */
1809
+ declare const AGENT_PAYLOAD_VERSION: 2;
1810
+ /**
1811
+ * Versions accepted by the validator. v1 payloads (the drag/drop surface) remain valid;
1812
+ * v2 adds the optional bus-envelope fields. Renderers narrow on `version` when they need
1813
+ * to.
1814
+ */
1815
+ declare const SUPPORTED_AGENT_PAYLOAD_VERSIONS: readonly number[];
1816
+ /**
1817
+ * Where a command surfaces. `'global'` = always offered. `{ appId }` = offered only when
1818
+ * the host's live `liveAppIds` set (passed to {@link AgentCommandRegistry.visible}) contains
1819
+ * that id. This lets a remote register its slash command at boot but only have it appear
1820
+ * in the palette while at least one of the remote's windows is open.
1821
+ */
1822
+ type AgentCommandScope = 'global' | {
1823
+ readonly appId: string;
1824
+ };
1825
+ /**
1826
+ * A slash command offered by the agent input palette. Commands are deliberately shallow
1827
+ * descriptors — the host (shell) decides what happens on Send. The descriptor's role is
1828
+ * to make the palette row renderable (icon, label, kbd hint, app badge) and matchable
1829
+ * (id, aliases, drop-kind suggestions) without coupling DS to any business logic.
1830
+ */
1831
+ interface AgentCommand {
1832
+ /** Stable id, kebab-case. Becomes the slash text after `/`, e.g. `/analyze-trend`. */
1833
+ readonly id: string;
1834
+ /** i18n key for the visible label, e.g. `agent.command.analyze_trend.label`. */
1835
+ readonly labelKey: string;
1836
+ /** i18n key for an optional sublabel / description shown beneath the label. */
1837
+ readonly descriptionKey?: string;
1838
+ /** PrimeIcons class, e.g. `pi-chart-line`. */
1839
+ readonly icon?: string;
1840
+ /** App badge label key — appears as a small tag, e.g. `agent.command.app_badge.circles`. */
1841
+ readonly appBadgeKey?: string;
1842
+ /** Optional kbd hint i18n key. */
1843
+ readonly kbdHintKey?: string;
1844
+ /** When the command is keyword-matched against drop payload kinds, list those kinds here. */
1845
+ readonly suggestForDropKinds?: readonly string[];
1846
+ /** Extra match terms beyond id + label, used by the fuzzy filter. */
1847
+ readonly aliases?: readonly string[];
1848
+ /** When `'send'`, the command is inserted as a bound prefix and executed on Send. */
1849
+ readonly executeOn: 'send';
1850
+ /** Optional client-side gate. Return false to hide the command in this scope. */
1851
+ readonly isVisible?: () => boolean;
1852
+ /**
1853
+ * Category B (PR3): when present, selecting this command invokes a
1854
+ * manifest-declared app skill instead of sending the composed text as a plain
1855
+ * message. The host dispatches a Twin message carrying
1856
+ * `system_context.slash_command_key = slashCommand.key` plus resolved context.
1857
+ * See {@link AgentCommandSlashSpec}.
1858
+ */
1859
+ readonly slashCommand?: AgentCommandSlashSpec;
1794
1860
  }
1795
1861
  /**
1796
- * Options narrowed to those carrying a `dontAskAgain` config the only shape
1797
- * accepted by `showAcknowledged()`.
1862
+ * A context binding that resolves one `system_context` value for a Category B
1863
+ * command at dispatch. Pure data so it travels app-agnostically in the
1864
+ * Controller's app federation metadata (no callbacks). Discriminated by `from`:
1865
+ *
1866
+ * - `route` — value from the owning app's current route param `path`. The
1867
+ * shell cannot read a federated remote's internal route, so route
1868
+ * bindings **degrade** in v1 (the skill asks for the missing id);
1869
+ * resolved only once a remote→shell route channel exists.
1870
+ * - `lookup` — the host opens the `/lookup` entity picker for `entity` and
1871
+ * writes the picked id into `system_context[key]` (picker-during-
1872
+ * dispatch is a v1 follow-up — degrades to "ask" until then).
1873
+ * - `constant` — a literal value written into `system_context[key]`.
1798
1874
  */
1799
- interface MessageBoxOptionsWithAcknowledgement extends MessageBoxOptions {
1800
- dontAskAgain: MessageBoxDontAskAgainConfig;
1875
+ type AgentCommandContextBinding = {
1876
+ readonly key: string;
1877
+ readonly from: 'route';
1878
+ readonly path: string;
1879
+ } | {
1880
+ readonly key: string;
1881
+ readonly from: 'lookup';
1882
+ readonly entity: string;
1883
+ readonly exclude?: readonly string[];
1884
+ readonly promptKey?: string;
1885
+ } | {
1886
+ readonly key: string;
1887
+ readonly from: 'constant';
1888
+ readonly value: string;
1889
+ };
1890
+ /**
1891
+ * Category B slash-command dispatch metadata (PR3). Travels app-agnostically in
1892
+ * the Controller's app federation metadata and is registered by the shell's
1893
+ * `RemoteManifestService` (the same path that registers `/lookup` descriptors) —
1894
+ * remotes do NOT self-register. When an {@link AgentCommand} carries this,
1895
+ * selecting it dispatches a Twin message with `system_context.slash_command_key
1896
+ * = key`, merged with the resolved `contextBindings`.
1897
+ */
1898
+ interface AgentCommandSlashSpec {
1899
+ /** Dispatched as `system_context.slash_command_key`; matches the agents-side
1900
+ * skill's `slash_command_key` (= its manifest_key). */
1901
+ readonly key: string;
1902
+ /** Reserved: a future confirm step before dispatch (manifest `requiresConfirmation`). */
1903
+ readonly requiresConfirmation?: boolean;
1904
+ /** Parameter sources resolved into `system_context` at dispatch. */
1905
+ readonly contextBindings?: readonly AgentCommandContextBinding[];
1801
1906
  }
1802
- interface MessageBoxButton {
1803
- label: string;
1804
- result: DialogResult;
1805
- variant?: 'primary' | 'danger' | 'default';
1907
+ /** What hosts pass to {@link AgentCommandRegistry.register}. Adds the scope to {@link AgentCommand}. */
1908
+ interface AgentCommandRegistration extends AgentCommand {
1909
+ readonly scope: AgentCommandScope;
1806
1910
  }
1807
- /** Shape returned by `showAcknowledged()` — pairs the dialog result with the checkbox state. */
1808
- interface DialogResultWithAcknowledgement {
1809
- readonly result: DialogResult;
1810
- readonly dontAskAgain: boolean;
1911
+ /** Disposable handle returned by {@link AgentCommandRegistry.register}. Idempotent `dispose()`. */
1912
+ interface AgentCommandHandle {
1913
+ dispose(): void;
1811
1914
  }
1812
- declare class MessageBoxService {
1813
- private readonly i18n;
1814
- readonly visible: _angular_core.WritableSignal<boolean>;
1815
- readonly title: _angular_core.WritableSignal<string>;
1816
- readonly message: _angular_core.WritableSignal<string>;
1817
- readonly icon: _angular_core.WritableSignal<MessageBoxIcon>;
1818
- readonly buttons: _angular_core.WritableSignal<MessageBoxButton[]>;
1819
- /**
1820
- * Active "Don't ask again" config populated only by `showAcknowledged()`.
1821
- * `show()` callers cannot reach this signal because the type system rejects
1822
- * `dontAskAgain` on the base `MessageBoxOptions`.
1823
- */
1824
- readonly dontAskAgain: _angular_core.WritableSignal<MessageBoxDontAskAgainConfig | undefined>;
1825
- /**
1826
- * Component-side checkbox state. The component (`MessageBoxComponent`) wires
1827
- * its own signal to this one; the service explicitly re-seeds it on every
1828
- * `_open()` so reusing a constant `options` literal across two opens does
1829
- * NOT leak the previous user's checkbox state through signal `===` dedupe.
1830
- * Exposed for the component to read/write; not for general callers.
1915
+ /**
1916
+ * How a lookup fetches candidate entities. The picker calls the app's existing
1917
+ * authenticated REST search endpoint (the same one the agent's MCP `*_list_brief`
1918
+ * tool wraps) through the shell's HttpClient — gateway routing + auth
1919
+ * interceptor apply. We deliberately do NOT route typeahead through MCP (agent-
1920
+ * shaped, agent-auth) or the dataset executor (aggregation-shaped, no fulltext).
1921
+ *
1922
+ * Field mapping is declarative because entities differ: Circles trends/signals
1923
+ * expose `/brief` endpoints returning `{ id, title, status }`, while scenarios
1924
+ * have no brief variant and return full objects with `titleEn` / `titleAr`. The
1925
+ * `displayField` / `secondaryField` indirection absorbs that per-entity skew so
1926
+ * one picker component serves them all.
1927
+ */
1928
+ interface LookupSearch {
1929
+ /**
1930
+ * Relative REST path the picker GETs, e.g. `/api/circles/trends/brief`. Must
1931
+ * be a relative path (no scheme/host) the SSRF guard at onboard time (when
1932
+ * the descriptor is manifest-backed) and the picker both reject absolute URLs.
1831
1933
  */
1832
- readonly dontAskAgainChecked: _angular_core.WritableSignal<boolean>;
1833
- private resolver;
1834
- show(options: MessageBoxOptions): Promise<DialogResult>;
1934
+ readonly endpoint: string;
1935
+ /** Query param carrying the typed text, e.g. `search`. */
1936
+ readonly queryParam: string;
1937
+ /** Static query params merged into every request, e.g. `{ pageSize: '10' }`. */
1938
+ readonly extraParams?: Readonly<Record<string, string>>;
1939
+ /** Response-item field holding the entity id. Default `id`. */
1940
+ readonly idField?: string;
1941
+ /** Response-item field holding the display label, e.g. `title` / `titleEn`. */
1942
+ readonly displayField: string;
1943
+ /** Optional response-item field for the chip's secondary line (status, category). */
1944
+ readonly secondaryField?: string;
1835
1945
  /**
1836
- * Opens a message box with a "Don't ask again" checkbox and resolves to both
1837
- * the dialog result and the checkbox state. Throws when `options.dontAskAgain`
1838
- * is missing the checkbox config is mandatory for this entry point. The
1839
- * compile-time signature already guarantees presence; the runtime check is
1840
- * defense-in-depth for callers that bypass the type system via `as never`.
1946
+ * Optional response-item field whose value is a *row-level* app id i.e. the
1947
+ * app that owns this individual entity, distinct from the descriptor's
1948
+ * {@link LookupDescriptor.appId} (which only names the app exposing the
1949
+ * lookup endpoint). Help articles are the motivating case: every article is
1950
+ * exposed by `help-center`, but each one was seeded by a *source* app's
1951
+ * manifest (Circles, Trends, …). Surfacing that per-row appId lets the
1952
+ * picker render a second source-app tag so the user can tell two
1953
+ * similarly-titled rows from different source apps apart at a glance.
1954
+ *
1955
+ * Resolved through {@link LookupResult.appId} and the shell's app registry
1956
+ * with the same fallback chain used for {@link LookupDescriptor.appId}.
1841
1957
  */
1842
- showAcknowledged(options: MessageBoxOptionsWithAcknowledgement): Promise<DialogResultWithAcknowledgement>;
1843
- resolve(result: DialogResult, dontAskAgain?: boolean): void;
1844
- private _open;
1845
- private resolveButtons;
1846
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<MessageBoxService, never>;
1847
- static ɵprov: _angular_core.ɵɵInjectableDeclaration<MessageBoxService>;
1958
+ readonly appIdField?: string;
1959
+ /**
1960
+ * Dotted path to the results array within the response body when it is
1961
+ * wrapped, e.g. `items` for `{ items: [...], total }`. Omit when the response
1962
+ * body IS the array.
1963
+ */
1964
+ readonly resultsPath?: string;
1848
1965
  }
1849
-
1850
- declare class MessageBoxComponent implements AfterViewInit {
1851
- service: MessageBoxService;
1852
- private elRef;
1853
- readonly MessageBoxIcon: typeof MessageBoxIcon;
1854
- readonly DialogResult: typeof DialogResult;
1855
- /** Mirror of the service's `dontAskAgain` config so the template can read it directly. */
1856
- readonly dontAskAgainConfig: _angular_core.Signal<_mohamedatia_fly_design_system.MessageBoxDontAskAgainConfig | undefined>;
1966
+ /**
1967
+ * A lookupable entity offered by the `/lookup` palette. Registered by the owning
1968
+ * app (a federation remote self-registers at boot, mirroring {@link AgentCommand})
1969
+ * or, once manifest-backed, projected from the app's `lookups[]` manifest section.
1970
+ *
1971
+ * The descriptor is a shallow, business-logic-free descriptor: it tells the
1972
+ * picker WHAT to search, WHERE it is offered, and HOW to map the response — the
1973
+ * picker owns the typeahead UX, the shell owns the HTTP call.
1974
+ */
1975
+ interface LookupDescriptor {
1857
1976
  /**
1858
- * User-driven checkbox state, owned by the service and re-seeded on every
1859
- * `_open()` so reusing a constant options literal cannot leak prior state.
1977
+ * Stable entity key, kebab/lower, e.g. `scenario`. Doubles as the `/lookup
1978
+ * <entity>` sub-token and the group key the picked ref is grouped under when
1979
+ * serialized for the agent.
1860
1980
  */
1861
- readonly dontAskAgainChecked: _angular_core.WritableSignal<boolean>;
1981
+ readonly entity: string;
1982
+ /** i18n key for the entity's display name in the picker / palette. */
1983
+ readonly labelKey: string;
1984
+ /** Optional PrimeIcons class for the picker row + chip. */
1985
+ readonly icon?: string;
1862
1986
  /**
1863
- * Concatenated id list for the dialog's `aria-describedby`. Always includes
1864
- * the message; appends the checkbox label id when the checkbox is rendered
1865
- * so screen readers announce the checkbox as part of the description.
1987
+ * Stable id of the app that exposes this lookup, e.g. `notes`, `calendar`,
1988
+ * `circles`. The picker resolves it to the app's display name via the shell's
1989
+ * app registry and renders an "exposed by …" badge so the user can see which
1990
+ * app owns the entity they're browsing (helps disambiguate when two apps
1991
+ * register a similar-sounding entity, e.g. both Tasks and Notes one day).
1992
+ *
1993
+ * Populated automatically by the shell's registration paths:
1994
+ * - `CORE_APP_LOOKUPS` stamps it per descriptor at hand-edit time.
1995
+ * - `RemoteManifestService` stamps it from the manifest entry's `id` so
1996
+ * federation remotes don't have to repeat the id in every descriptor.
1997
+ *
1998
+ * Falls back to {@link appBadgeKey} (a locale-resolved literal) when an
1999
+ * entity has no first-class home in the shell's app registry — e.g. `user`,
2000
+ * `app-agent`, `robot`. When neither is set the picker omits the badge.
1866
2001
  */
1867
- readonly ariaDescribedBy: _angular_core.Signal<"mb-message mb-dont-ask" | "mb-message">;
1868
- private previouslyFocused;
1869
- ngAfterViewInit(): void;
1870
- onEscape(): void;
1871
- onBackdropClick(): void;
1872
- onButtonClick(result: DialogResult): void;
1873
- onDontAskAgainToggle(ev: Event): void;
1874
- iconClass(): string;
1875
- private focusPrimaryButton;
1876
- private restoreFocus;
1877
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<MessageBoxComponent, never>;
1878
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<MessageBoxComponent, "fly-message-box", never, {}, {}, never, never, true, never>;
2002
+ readonly appId?: string;
2003
+ /**
2004
+ * Optional i18n key the picker uses for the "exposed by …" badge **when
2005
+ * {@link appId} is absent or unknown to the shell's app registry**. Lets
2006
+ * entities that don't map to a single app (Users, Robots, App Agents) still
2007
+ * surface a meaningful badge instead of silently omitting it. The picker
2008
+ * resolves the key via the shared i18n service so the badge follows the
2009
+ * user's locale.
2010
+ */
2011
+ readonly appBadgeKey?: string;
2012
+ /**
2013
+ * Advisory MCP tool-key prefixes the agent should prefer when the user
2014
+ * references this entity via `/lookup` (e.g. `['dashboard.reports']`). The
2015
+ * shell folds these into the turn's `mcp_scope` so the Twin self-serves the
2016
+ * owning app's tools — fetching and analysing the referenced entity itself —
2017
+ * instead of defaulting to a specialist-Robot consult for "tell me more"
2018
+ * style prompts. Same dot-namespaced prefix vocabulary as
2019
+ * {@link AgentMcpScope.apis}. Omit for entities with no first-class MCP tool
2020
+ * family (e.g. `user`, `robot`).
2021
+ */
2022
+ readonly mcpApis?: readonly string[];
2023
+ /**
2024
+ * Optional in-app deep-link route TEMPLATE for this entity's detail page,
2025
+ * e.g. `'/signals/{id}'`. When present, the desktop shell turns an agent's
2026
+ * inline reference to this entity — the `flyos:<appId>.<entity>/<id>`
2027
+ * anchors the agents backend emits in chat answers — into a launchable
2028
+ * link: the single `{id}` placeholder is substituted with the referenced
2029
+ * entity's id (URL-encoded) and the owning {@link appId} is launched on
2030
+ * that route via the shell launcher.
2031
+ *
2032
+ * Omit for entities with no standalone detail page — their references then
2033
+ * render as plain text (graceful degrade; never a dead link). The owning
2034
+ * app declares this once in its `lookups[]` manifest entry, so a remote
2035
+ * becomes agent-deep-linkable without any shell or design-system change.
2036
+ * Only `{id}` is substituted here — richer parameterisation rides the
2037
+ * deep-link `params` channel, not this template.
2038
+ */
2039
+ readonly deepLinkRoute?: string;
2040
+ /** How to fetch + map candidates. */
2041
+ readonly search: LookupSearch;
1879
2042
  }
1880
-
1881
- /** Full-bleed loading overlay for window content (shell) or embedded hosts. */
1882
- declare class FlyBlockUiComponent {
1883
- /** When false, the overlay is not rendered (host may use @if instead). */
1884
- active: _angular_core.InputSignal<boolean>;
1885
- /** i18n key for status text; empty uses `common.loading`. */
1886
- messageKey: _angular_core.InputSignal<string>;
1887
- readonly resolvedMessageKey: _angular_core.Signal<string>;
1888
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<FlyBlockUiComponent, never>;
1889
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<FlyBlockUiComponent, "fly-block-ui", never, { "active": { "alias": "active"; "required": true; "isSignal": true; }; "messageKey": { "alias": "messageKey"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
2043
+ /** What hosts pass to the lookup registry. Adds the scope to {@link LookupDescriptor}. */
2044
+ interface LookupRegistration extends LookupDescriptor {
2045
+ /**
2046
+ * Affinity hint, NOT a visibility gate.
2047
+ *
2048
+ * Unlike {@link AgentCommandScope} where `{appId}` HIDES a command unless the
2049
+ * app is live — lookup scope is a *priority hint*. Every registered lookup is
2050
+ * always offered in `/lookup`; when the app named by `{appId}` is in the host's
2051
+ * live app set, that lookup sorts to the **top** of the entity picker so the
2052
+ * "what am I working on right now?" entities surface first. `'global'` lookups
2053
+ * have no affinity and sort after app-affinity matches.
2054
+ *
2055
+ * Rationale: OS-core entities (note, calendar event, file) are always
2056
+ * referenceable — there's no "open the app first" condition the way there is
2057
+ * for federated remotes — so a visibility gate would just produce a confusing
2058
+ * empty state. Affinity-as-sort preserves the "Circles is open → prefer
2059
+ * scenarios/trends/signals" intuition without hiding the rest.
2060
+ */
2061
+ readonly scope: AgentCommandScope;
1890
2062
  }
1891
-
1892
- /**
1893
- * Metadata returned by Files Manager after a successful upload or metadata query.
1894
- * Mirrors the `FileMetadataDto` shape from `GET /api/files/{id}` and `POST /api/files/upload`.
1895
- */
1896
- interface FlyFileInfo {
1897
- id: string;
1898
- fileName: string;
1899
- contentType: string;
1900
- sizeBytes: number;
1901
- sourceApp: string;
1902
- sourceEntityType?: string;
1903
- sourceEntityId?: string;
1904
- uploadedByUserId?: string;
1905
- correlationId?: string;
1906
- isConfirmed: boolean;
1907
- version: number;
1908
- scanStatus: string;
1909
- createdAt: string;
1910
- folderId?: string;
1911
- hasErrors: boolean;
2063
+ /** One resolved row the picker returns once the user selects a candidate. */
2064
+ interface LookupResult {
2065
+ /** The entity kind (echoes {@link LookupDescriptor.entity}). */
2066
+ readonly entity: string;
2067
+ /** Selected entity id. */
2068
+ readonly id: string;
2069
+ /** Selected entity's display label. */
2070
+ readonly label: string;
2071
+ /** Optional secondary detail (status / category). */
2072
+ readonly secondary?: string;
2073
+ /**
2074
+ * Row-level source app id (e.g. `circles` for an article seeded by Circles'
2075
+ * manifest). Populated when the descriptor sets {@link LookupSearch.appIdField}
2076
+ * and the response item carries a non-empty value. The picker renders it as
2077
+ * a second app tag alongside the descriptor-level badge so the user can see
2078
+ * "this Help-Center article was contributed by Circles" without opening it.
2079
+ */
2080
+ readonly appId?: string;
2081
+ }
2082
+ /** Disposable handle returned by the lookup registry. Idempotent `dispose()`. */
2083
+ interface LookupHandle {
2084
+ dispose(): void;
1912
2085
  }
1913
-
1914
2086
  /**
1915
- * Image upload component with built-in cropperjs cropping modal.
2087
+ * The wire envelope used by both the drag/drop surface and the imperative
2088
+ * {@link AgentActionBus}. Renderers narrow on `kind`; mismatches fall back to
2089
+ * `plainTextFallback`.
1916
2090
  *
1917
- * Usage:
1918
- * ```html
1919
- * <fly-image-upload
1920
- * [aspectRatio]="16/9"
1921
- * [currentImageId]="trend.coverImageId"
1922
- * sourceApp="circles"
1923
- * sourceEntityType="trend"
1924
- * (uploaded)="onImageUploaded($event)"
1925
- * (removed)="onImageRemoved()"
1926
- * />
1927
- * ```
1928
- */
1929
- declare class FlyImageUploadComponent {
1930
- private http;
1931
- private injector;
1932
- aspectRatio: _angular_core.InputSignal<number>;
1933
- maxSizeBytes: _angular_core.InputSignal<number>;
1934
- currentImageId: _angular_core.InputSignal<string | null>;
1935
- sourceApp: _angular_core.InputSignal<string>;
1936
- sourceEntityType: _angular_core.InputSignal<string | null>;
1937
- sourceEntityId: _angular_core.InputSignal<string | null>;
1938
- uploaded: _angular_core.OutputEmitterRef<FlyFileInfo>;
1939
- removed: _angular_core.OutputEmitterRef<void>;
1940
- uploading: _angular_core.WritableSignal<boolean>;
1941
- error: _angular_core.WritableSignal<string | null>;
1942
- showCropper: _angular_core.WritableSignal<boolean>;
1943
- rawImageUrl: _angular_core.WritableSignal<string>;
1944
- localBlob: _angular_core.WritableSignal<string | null>;
1945
- fileInput: _angular_core.Signal<ElementRef<HTMLInputElement> | undefined>;
1946
- cropImage: _angular_core.Signal<ElementRef<HTMLImageElement> | undefined>;
1947
- private cropper;
1948
- private selectedFile;
1949
- /** Resolved preview URL — uses blob for local uploads, fetches authenticated for existing images */
1950
- previewUrl: _angular_core.WritableSignal<string | null>;
1951
- constructor();
1952
- sizeHint: _angular_core.Signal<string>;
1953
- triggerFileInput(): void;
1954
- onDragOver(e: DragEvent): void;
1955
- onDrop(e: DragEvent): void;
1956
- onFileSelected(e: Event): void;
1957
- removeImage(): void;
1958
- cancelCrop(): void;
1959
- applyCrop(): void;
1960
- private processFile;
1961
- private initCropper;
1962
- private destroyCropper;
1963
- private uploadFile;
1964
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<FlyImageUploadComponent, never>;
1965
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<FlyImageUploadComponent, "fly-image-upload", never, { "aspectRatio": { "alias": "aspectRatio"; "required": false; "isSignal": true; }; "maxSizeBytes": { "alias": "maxSizeBytes"; "required": false; "isSignal": true; }; "currentImageId": { "alias": "currentImageId"; "required": false; "isSignal": true; }; "sourceApp": { "alias": "sourceApp"; "required": false; "isSignal": true; }; "sourceEntityType": { "alias": "sourceEntityType"; "required": false; "isSignal": true; }; "sourceEntityId": { "alias": "sourceEntityId"; "required": false; "isSignal": true; }; }, { "uploaded": "uploaded"; "removed": "removed"; }, never, never, true, never>;
1966
- }
1967
-
1968
- interface UploadSlot {
1969
- file: File;
1970
- progress: number;
1971
- status: 'uploading' | 'done' | 'error';
1972
- info?: FlyFileInfo;
1973
- error?: string;
1974
- }
1975
- /**
1976
- * Multi-file upload with drag-drop, progress, and validation.
2091
+ * The base fields (v1) describe **what** is being handed to the agent panel.
2092
+ * The v2 fields describe **how the agent should treat it** — `userMessage`
2093
+ * scopes the user-visible bubble, `systemContext` extends the system prompt,
2094
+ * `attachments` decorate the message with typed chips, and `mcpScope` hints
2095
+ * the agent toward a tool family. All v2 fields are optional so existing
2096
+ * v1 (drag/drop) payloads remain valid envelopes.
1977
2097
  *
1978
- * Usage:
1979
- * ```html
1980
- * <fly-file-upload
1981
- * [maxFiles]="5"
1982
- * [maxFileSizeBytes]="5242880"
1983
- * accept=".pdf,.docx,.xlsx"
1984
- * [(files)]="trend.attachments"
1985
- * sourceApp="circles"
1986
- * sourceEntityType="trend"
1987
- * (filesChanged)="onAttachmentsChanged($event)"
1988
- * />
1989
- * ```
2098
+ * Caps (see {@link AgentPayloadLimits}):
2099
+ * - JSON total 32 KB
2100
+ * - plainTextFallback 8 KB
2101
+ * - per-string field 4 KB
2102
+ * - userMessage 280 chars
2103
+ * - systemContext 32 entries × 4 KB per value, 8 KB total serialized
2104
+ * - attachments 4 entries, kind-dependent inner caps
2105
+ * - mcpScope.apis 5 prefixes × 128 chars
2106
+ *
2107
+ * The cap math is split per-section so an oversize attachment fails fast at the
2108
+ * attachment site instead of the whole envelope; field paths are dotted (see
2109
+ * {@link AgentPayloadValidationResult}).
1990
2110
  */
1991
- declare class FlyFileUploadComponent {
1992
- private http;
1993
- maxFiles: _angular_core.InputSignal<number>;
1994
- maxFileSizeBytes: _angular_core.InputSignal<number>;
1995
- accept: _angular_core.InputSignal<string>;
1996
- sourceApp: _angular_core.InputSignal<string>;
1997
- sourceEntityType: _angular_core.InputSignal<string | null>;
1998
- sourceEntityId: _angular_core.InputSignal<string | null>;
1999
- /** Optional: provide file IDs to auto-fetch metadata for pre-existing files (edit mode). */
2000
- existingFileIds: _angular_core.InputSignal<string[] | null>;
2001
- /** Two-way model for completed file metadata. */
2002
- files: _angular_core.ModelSignal<FlyFileInfo[]>;
2003
- filesChanged: _angular_core.OutputEmitterRef<FlyFileInfo[]>;
2004
- error: _angular_core.WritableSignal<string | null>;
2005
- dragging: _angular_core.WritableSignal<boolean>;
2006
- slots: _angular_core.WritableSignal<UploadSlot[]>;
2007
- /** Pre-existing files loaded from the entity (before any new uploads this session). */
2008
- existingFiles: _angular_core.WritableSignal<FlyFileInfo[]>;
2009
- fileInput: _angular_core.Signal<ElementRef<HTMLInputElement> | undefined>;
2010
- constructor();
2011
- allSlots: _angular_core.Signal<UploadSlot[]>;
2012
- canAddMore: _angular_core.Signal<boolean>;
2013
- limitHint: _angular_core.Signal<string>;
2014
- triggerFileInput(): void;
2015
- onDragOver(e: DragEvent): void;
2016
- onDragLeave(e: DragEvent): void;
2017
- onDrop(e: DragEvent): void;
2018
- onFilesSelected(e: Event): void;
2019
- removeSlot(slot: UploadSlot): void;
2020
- removeExisting(f: FlyFileInfo): void;
2021
- iconFor(slot: UploadSlot): string;
2022
- iconForInfo(f: FlyFileInfo): string;
2023
- formatFileSize(bytes: number): string;
2024
- private processFiles;
2025
- private uploadFile;
2026
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<FlyFileUploadComponent, never>;
2027
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<FlyFileUploadComponent, "fly-file-upload", never, { "maxFiles": { "alias": "maxFiles"; "required": false; "isSignal": true; }; "maxFileSizeBytes": { "alias": "maxFileSizeBytes"; "required": false; "isSignal": true; }; "accept": { "alias": "accept"; "required": false; "isSignal": true; }; "sourceApp": { "alias": "sourceApp"; "required": false; "isSignal": true; }; "sourceEntityType": { "alias": "sourceEntityType"; "required": false; "isSignal": true; }; "sourceEntityId": { "alias": "sourceEntityId"; "required": false; "isSignal": true; }; "existingFileIds": { "alias": "existingFileIds"; "required": false; "isSignal": true; }; "files": { "alias": "files"; "required": false; "isSignal": true; }; }, { "files": "filesChange"; "filesChanged": "filesChanged"; }, never, never, true, never>;
2111
+ interface AgentDragPayload<T = unknown> {
2112
+ /** Domain-stable kind, e.g. `circles.trend`. */
2113
+ readonly kind: string;
2114
+ /** Originating appId. Must match an entry in the host's app registry. */
2115
+ readonly appId: string;
2116
+ /** Frozen format version. Accepted: 1 or {@link AGENT_PAYLOAD_VERSION} (2). */
2117
+ readonly version: number;
2118
+ /** Domain object. Renderers narrow on `kind`. */
2119
+ readonly payload: T;
2120
+ /** Plain-text fallback written to the dataTransfer alongside the typed MIME. */
2121
+ readonly plainTextFallback: string;
2122
+ /** Optional command ids to highlight when this payload is dropped. */
2123
+ readonly suggestedCommandIds?: readonly string[];
2124
+ /**
2125
+ * Short, locale-resolved string the dispatcher wants shown in the user's
2126
+ * chat bubble. The agent panel uses it as the visible message text; when
2127
+ * absent, the panel falls back to a generic per-verb default
2128
+ * (e.g. "Tell me more about this"). Cap 280 chars — chip-sized, not essay.
2129
+ *
2130
+ * This is the ONLY field that should ever surface to the user verbatim.
2131
+ * Everything else (systemContext, attachment bodies, mcpScope) is wire-only.
2132
+ */
2133
+ readonly userMessage?: string;
2134
+ /**
2135
+ * Flat key→string facts the dispatcher wants injected into the agent's
2136
+ * system prompt for this turn. Keys are dot-namespaced (e.g.
2137
+ * `chart.name`, `chart.type`, `chart.dimension`) to keep the model's
2138
+ * mental schema flat and grep-friendly. Values are strings — booleans,
2139
+ * numbers, and dates must be pre-serialized at the call site so the
2140
+ * dispatcher owns the formatting (timezone, locale, number style).
2141
+ *
2142
+ * Cap: 32 entries, 4 KB per value, 8 KB total when serialized.
2143
+ *
2144
+ * NOT user-visible. The agent panel may transiently embed this as an
2145
+ * `[Internal context]` block in the wire content while the backend
2146
+ * learns to consume the dedicated field, but never renders it in the
2147
+ * user bubble.
2148
+ */
2149
+ readonly systemContext?: Readonly<Record<string, string>>;
2150
+ /**
2151
+ * Typed attachments rendered as a chip strip under the user's outgoing
2152
+ * message bubble. Each entry has a `kind` discriminator and a `label`
2153
+ * (locale-resolved by the dispatcher). v2 ships `json` + `text`;
2154
+ * `image` and `file` are reserved — their interfaces are stable so
2155
+ * future callers don't need a contract bump, but the panel may render
2156
+ * a generic chip for them until per-kind renderers land.
2157
+ *
2158
+ * Cap: 4 entries per envelope. Per-kind body caps:
2159
+ * - json: 16 KB serialized
2160
+ * - text: 8 KB UTF-8
2161
+ * - image / file: dataUrl ≤ 32 KB (small previews; large media stays in
2162
+ * the files-manager and is referenced by id)
2163
+ */
2164
+ readonly attachments?: readonly AgentEnvelopeAttachment[];
2165
+ /**
2166
+ * Advisory MCP scope. The agent service injects these prefixes into the
2167
+ * system prompt as a tool-selection hint ("prefer tools matching
2168
+ * `dashboard.reports.*` for this turn") — NOT a hard filter. The agent
2169
+ * remains free to pick any tool; this just biases the first guess so a
2170
+ * dashboard explain doesn't waste a tool-call probing Notes APIs first.
2171
+ *
2172
+ * Cap: 5 prefixes × 128 chars. Prefixes should match gateway-aggregated
2173
+ * OpenAPI tag/path roots so they line up with the names the MCP server
2174
+ * exposes — see `src/backend/gateway` Swagger aggregation + the dynamic
2175
+ * loader in `src/backend/mcp-server`.
2176
+ */
2177
+ readonly mcpScope?: AgentMcpScope;
2178
+ /**
2179
+ * Optional deep-link route the originating app can use to re-open the
2180
+ * source object. When set, payload chips (and any other renderer that
2181
+ * surfaces the envelope to the user) become clickable — clicking calls
2182
+ * `ShellLauncherService.launch({ appId, route: deepLinkRoute })` so the
2183
+ * target app opens / focuses and navigates to the originating object.
2184
+ *
2185
+ * Shape constraints (mirror `DeepLinkService.isValidRoute`):
2186
+ * - starts with `/`
2187
+ * - ≤ {@link AgentPayloadLimits.maxDeepLinkRouteBytes} bytes (default
2188
+ * 1024) — matches the route limit on the wider shell deep-link
2189
+ * contract so this field can be handed straight to the launcher.
2190
+ * - no `..` segments
2191
+ * - no `//` runs
2192
+ * - no scheme-like prefixes (`/javascript:`, `/data:`, `/http:`, `/https:`)
2193
+ *
2194
+ * The DS validator enforces only the byte cap — full route syntax
2195
+ * validation is owned by the shell side (`DeepLinkService`) because the
2196
+ * DS package is shell-agnostic and shouldn't grow a second copy of the
2197
+ * URL grammar. Apps building envelopes are expected to stamp routes that
2198
+ * match their own internal route schema (e.g. dashboard publishes
2199
+ * `/reports/{id}` and `/custom/{id}`); see `skills/cross-app-deep-linking.md`.
2200
+ *
2201
+ * Backwards-compat: absent on v1 payloads and on v2 payloads built
2202
+ * before this field was added. Persisted JSONB chips without the field
2203
+ * remain non-clickable; new chips light up automatically.
2204
+ */
2205
+ readonly deepLinkRoute?: string;
2028
2206
  }
2029
-
2030
2207
  /**
2031
- * Agent input contracts.
2032
- *
2033
- * These types define the wire and DI surface for the new `<fly-agent-input>` orchestrator
2034
- * (Phase 2+). Phase 1 ships only the contracts: payload envelope, command/drop registry
2035
- * shapes, and chip-host inputs. The concrete components consume them later.
2036
- *
2037
- * Design rules:
2038
- * - All fields are `readonly` — the registries store these in signal stores and we never
2039
- * want a host mutating after registration. Hosts construct fresh objects to update.
2040
- * - The discriminated kinds (`scope`, `mode`, `kind`) carry the entire variance — no
2041
- * boolean flags. New variants extend the union without breaking existing consumers.
2042
- * - The `Type<AgentChipHostInputs<T>>` shape is intentional: chip components declare
2043
- * `payload`, `mode`, optional `onRemove` as Angular `input()` signals; the registry
2044
- * wires them via `NgComponentOutlet` inputs in the consumer. The component reference
2045
- * itself never leaks across the federation boundary by value — only by class identity.
2208
+ * Canonical name for the bus-side envelope. v2 callers should reference this
2209
+ * over {@link AgentDragPayload} for clarity — the underlying shape is
2210
+ * identical, but the name signals "this is going to the agent, not to a
2211
+ * drop zone." The alias is intentional: one wire shape, two semantic uses.
2046
2212
  */
2047
- /** Frozen MIME used by `flyAgentDraggable` and the drop-zone reader. Never change without a DS major. */
2048
- declare const AGENT_DRAG_MIME: "application/x-fly-agent-payload+json";
2213
+ type AgentMessageEnvelope<T = unknown> = AgentDragPayload<T>;
2049
2214
  /**
2050
- * Frozen payload envelope version.
2215
+ * Typed attachment discriminator for {@link AgentDragPayload.attachments}.
2051
2216
  *
2052
- * v1minimal drag payload: kind / appId / version / payload / plainTextFallback /
2053
- * suggestedCommandIds. Still used by the drag/drop surface.
2217
+ * - `json` structured data the panel renders as a "code-ish" chip the
2218
+ * user can expand. Used for chart snapshots, query results, etc.
2219
+ * - `text` — short utterance / excerpt with optional MIME. Used when the
2220
+ * dispatcher wants the chip to preview a note paragraph, log line,
2221
+ * code snippet, etc.
2222
+ * - `image` / `file` — reserved. Stable interface; renderers added per
2223
+ * downstream caller (the panel may fall back to a generic icon-chip).
2054
2224
  *
2055
- * v2bus envelope ({@link AgentMessageEnvelope}). Adds optional `userMessage`,
2056
- * `systemContext`, `attachments`, `mcpScope` so a dispatcher can give the agent
2057
- * rich context without polluting the user-visible message bubble. v2 is a
2058
- * superset of v1 — every v1 payload is a valid v2 payload — so the version
2059
- * number ratchets forward without breaking existing callers.
2225
+ * Every kind carries `label` that's what shows on the chip face and what
2226
+ * a11y trees announce.
2060
2227
  */
2061
- declare const AGENT_PAYLOAD_VERSION: 2;
2228
+ type AgentEnvelopeAttachment = {
2229
+ readonly kind: 'json';
2230
+ readonly label: string;
2231
+ readonly json: unknown;
2232
+ } | {
2233
+ readonly kind: 'text';
2234
+ readonly label: string;
2235
+ readonly text: string;
2236
+ readonly mimeType?: string;
2237
+ } | {
2238
+ readonly kind: 'image';
2239
+ readonly label: string;
2240
+ /** `data:` URL — small previews only. Large media stays in files-manager. */
2241
+ readonly dataUrl: string;
2242
+ readonly mimeType: string;
2243
+ } | {
2244
+ readonly kind: 'file';
2245
+ readonly label: string;
2246
+ readonly dataUrl: string;
2247
+ readonly mimeType: string;
2248
+ readonly bytes: number;
2249
+ };
2250
+ /** Advisory tool-selection hint for {@link AgentDragPayload.mcpScope}. */
2251
+ interface AgentMcpScope {
2252
+ /**
2253
+ * Prefixes of gateway-aggregated OpenAPI tags / path roots — e.g.
2254
+ * `dashboard.reports`, `notes.documents`. The agent service treats these
2255
+ * as a soft preference, not a hard filter.
2256
+ */
2257
+ readonly apis: readonly string[];
2258
+ }
2062
2259
  /**
2063
- * Versions accepted by the validator. v1 payloads (the drag/drop surface) remain valid;
2064
- * v2 adds the optional bus-envelope fields. Renderers narrow on `version` when they need
2065
- * to.
2260
+ * Where a chip is being rendered. `inline` = inside the input chip tray (removable);
2261
+ * `message` = embedded in a sent message bubble (not removable).
2066
2262
  */
2067
- declare const SUPPORTED_AGENT_PAYLOAD_VERSIONS: readonly number[];
2263
+ type AgentDropChipMode = 'inline' | 'message';
2068
2264
  /**
2069
- * Where a command surfaces. `'global'` = always offered. `{ appId }` = offered only when
2070
- * the host's live `liveAppIds` set (passed to {@link AgentCommandRegistry.visible}) contains
2071
- * that id. This lets a remote register its slash command at boot but only have it appear
2072
- * in the palette while at least one of the remote's windows is open.
2265
+ * Public input shape for chip-renderer components. Components declare matching
2266
+ * `input()` signals; the registry wires them via `NgComponentOutlet`.
2073
2267
  */
2074
- type AgentCommandScope = 'global' | {
2075
- readonly appId: string;
2076
- };
2268
+ interface AgentChipHostInputs<T = unknown> {
2269
+ payload: AgentDragPayload<T>;
2270
+ mode: AgentDropChipMode;
2271
+ /** Called when the user clicks the chip's remove control (only in inline mode). */
2272
+ onRemove?: () => void;
2273
+ }
2077
2274
  /**
2078
- * A slash command offered by the agent input palette. Commands are deliberately shallow
2079
- * descriptors the host (shell) decides what happens on Send. The descriptor's role is
2080
- * to make the palette row renderable (icon, label, kbd hint, app badge) and matchable
2081
- * (id, aliases, drop-kind suggestions) without coupling DS to any business logic.
2275
+ * Keyboard-alternative draggable item. Hosts publish these via
2276
+ * {@link AgentDropRegistry.publishDraggables} so the "Attach from app…" menu can offer
2277
+ * them when pointer drag isn't available.
2082
2278
  */
2083
- interface AgentCommand {
2084
- /** Stable id, kebab-case. Becomes the slash text after `/`, e.g. `/analyze-trend`. */
2279
+ interface AgentDraggableItem<T = unknown> {
2280
+ /** Stable id within its app. Used as a list key in the kbd menu. */
2085
2281
  readonly id: string;
2086
- /** i18n key for the visible label, e.g. `agent.command.analyze_trend.label`. */
2087
2282
  readonly labelKey: string;
2088
- /** i18n key for an optional sublabel / description shown beneath the label. */
2089
- readonly descriptionKey?: string;
2090
- /** PrimeIcons class, e.g. `pi-chart-line`. */
2091
2283
  readonly icon?: string;
2092
- /** App badge label key appears as a small tag, e.g. `agent.command.app_badge.circles`. */
2093
- readonly appBadgeKey?: string;
2094
- /** Optional kbd hint i18n key. */
2095
- readonly kbdHintKey?: string;
2096
- /** When the command is keyword-matched against drop payload kinds, list those kinds here. */
2097
- readonly suggestForDropKinds?: readonly string[];
2098
- /** Extra match terms beyond id + label, used by the fuzzy filter. */
2099
- readonly aliases?: readonly string[];
2100
- /** When `'send'`, the command is inserted as a bound prefix and executed on Send. */
2101
- readonly executeOn: 'send';
2102
- /** Optional client-side gate. Return false to hide the command in this scope. */
2103
- readonly isVisible?: () => boolean;
2284
+ /** Builds the payload the moment the user picks the item. */
2285
+ build(): AgentDragPayload<T>;
2286
+ }
2287
+ /** Registry input shape for binding a chip-renderer component to a kind+appId pair. */
2288
+ interface AgentDropRendererRegistration<T = unknown> {
2289
+ readonly kind: string;
2290
+ readonly appId: string;
2291
+ readonly component: Type<AgentChipHostInputs<T>>;
2292
+ }
2293
+ /**
2294
+ * Caps applied by {@link validateAgentPayload} / {@link trimAgentPayload}. The defaults
2295
+ * trade off "fits comfortably in a single MQ frame" against "covers a richly-populated
2296
+ * trend or note card". Hosts may pass a partial override.
2297
+ */
2298
+ interface AgentPayloadLimits {
2299
+ /** Cap on the JSON.stringify(envelope) byte length. Default 32 KB. */
2300
+ readonly maxJsonBytes: number;
2301
+ /** Cap on the plainTextFallback byte length. Default 8 KB. */
2302
+ readonly maxPlainTextFallbackBytes: number;
2303
+ /** Cap on any single string field inside payload (recursive). Default 4 KB. */
2304
+ readonly maxStringFieldBytes: number;
2305
+ /** Cap on `userMessage` UTF-8 byte length. Default 280 chars (~1.1 KB). */
2306
+ readonly maxUserMessageBytes: number;
2307
+ /** Max entries in `systemContext`. Default 32. */
2308
+ readonly maxSystemContextEntries: number;
2309
+ /** Cap on any single systemContext value's UTF-8 byte length. Default 4 KB. */
2310
+ readonly maxSystemContextValueBytes: number;
2311
+ /** Cap on the full JSON.stringify(systemContext). Default 8 KB. */
2312
+ readonly maxSystemContextJsonBytes: number;
2313
+ /** Max attachments per envelope. Default 4. */
2314
+ readonly maxAttachments: number;
2315
+ /** Cap on a `json` attachment's serialized body. Default 16 KB. */
2316
+ readonly maxAttachmentJsonBytes: number;
2317
+ /** Cap on a `text` attachment's body bytes. Default 8 KB. */
2318
+ readonly maxAttachmentTextBytes: number;
2319
+ /** Cap on an `image` / `file` attachment's dataUrl bytes. Default 32 KB. */
2320
+ readonly maxAttachmentDataUrlBytes: number;
2321
+ /** Max prefixes in `mcpScope.apis`. Default 5. */
2322
+ readonly maxMcpScopeApis: number;
2323
+ /** Cap on any single mcpScope prefix string. Default 128 chars. */
2324
+ readonly maxMcpScopeApiBytes: number;
2104
2325
  /**
2105
- * Category B (PR3): when present, selecting this command invokes a
2106
- * manifest-declared app skill instead of sending the composed text as a plain
2107
- * message. The host dispatches a Twin message carrying
2108
- * `system_context.slash_command_key = slashCommand.key` plus resolved context.
2109
- * See {@link AgentCommandSlashSpec}.
2326
+ * Cap on `deepLinkRoute` UTF-8 byte length. Default 1024 bytes — matches
2327
+ * the route limit on `DeepLinkService.isValidRoute` so this field can be
2328
+ * handed straight to the shell launcher without a second resize.
2110
2329
  */
2111
- readonly slashCommand?: AgentCommandSlashSpec;
2330
+ readonly maxDeepLinkRouteBytes: number;
2112
2331
  }
2332
+ declare const DEFAULT_AGENT_PAYLOAD_LIMITS: AgentPayloadLimits;
2113
2333
  /**
2114
- * A context binding that resolves one `system_context` value for a Category B
2115
- * command at dispatch. Pure data so it travels app-agnostically in the
2116
- * Controller's app federation metadata (no callbacks). Discriminated by `from`:
2117
- *
2118
- * - `route` value from the owning app's current route param `path`. The
2119
- * shell cannot read a federated remote's internal route, so route
2120
- * bindings **degrade** in v1 (the skill asks for the missing id);
2121
- * resolved only once a remote→shell route channel exists.
2122
- * - `lookup` — the host opens the `/lookup` entity picker for `entity` and
2123
- * writes the picked id into `system_context[key]` (picker-during-
2124
- * dispatch is a v1 follow-up — degrades to "ask" until then).
2125
- * - `constant` — a literal value written into `system_context[key]`.
2126
- */
2127
- type AgentCommandContextBinding = {
2128
- readonly key: string;
2129
- readonly from: 'route';
2130
- readonly path: string;
2131
- } | {
2132
- readonly key: string;
2133
- readonly from: 'lookup';
2134
- readonly entity: string;
2135
- readonly exclude?: readonly string[];
2136
- readonly promptKey?: string;
2334
+ * Stable failure reasons emitted by {@link validateAgentPayload}.
2335
+ * - `invalid_version` `version` !== {@link AGENT_PAYLOAD_VERSION}.
2336
+ * - `invalid_kind` `kind` is empty / not a string.
2337
+ * - `field_too_large` — a string field inside `payload` exceeds `maxStringFieldBytes`.
2338
+ * - `fallback_too_large` `plainTextFallback` exceeds `maxPlainTextFallbackBytes`.
2339
+ * - `json_too_large` the full JSON.stringify(envelope) exceeds `maxJsonBytes`.
2340
+ */
2341
+ type AgentPayloadValidationResult = {
2342
+ readonly ok: true;
2137
2343
  } | {
2138
- readonly key: string;
2139
- readonly from: 'constant';
2140
- readonly value: string;
2344
+ readonly ok: false;
2345
+ readonly reason: 'json_too_large' | 'fallback_too_large' | 'field_too_large' | 'invalid_version' | 'invalid_kind' | 'user_message_too_large' | 'system_context_too_many_entries' | 'system_context_value_too_large' | 'system_context_json_too_large' | 'too_many_attachments' | 'attachment_invalid_kind' | 'attachment_json_too_large' | 'attachment_text_too_large' | 'attachment_data_url_too_large' | 'mcp_scope_too_many_apis' | 'mcp_scope_api_too_large' | 'deep_link_route_too_large' | 'deep_link_route_invalid_shape';
2346
+ /** Dotted property-access path to the offending field, e.g. `payload.title` or `payload.tags[2]`. NOT RFC 6901 JSON Pointer. */
2347
+ readonly fieldPath?: string;
2348
+ readonly actualBytes?: number;
2349
+ readonly limitBytes?: number;
2141
2350
  };
2351
+
2142
2352
  /**
2143
- * Category B slash-command dispatch metadata (PR3). Travels app-agnostically in
2144
- * the Controller's app federation metadata and is registered by the shell's
2145
- * `RemoteManifestService` (the same path that registers `/lookup` descriptors)
2146
- * remotes do NOT self-register. When an {@link AgentCommand} carries this,
2147
- * selecting it dispatches a Twin message with `system_context.slash_command_key
2148
- * = key`, merged with the resolved `contextBindings`.
2353
+ * Emitted by {@link EntityLookupComponent} when the user picks an entity that
2354
+ * resolves to an in-app deep link everything a consumer needs to insert a
2355
+ * clickable `flyos:` link into an editor or message, without touching the
2356
+ * lookup registry itself.
2149
2357
  */
2150
- interface AgentCommandSlashSpec {
2151
- /** Dispatched as `system_context.slash_command_key`; matches the agents-side
2152
- * skill's `slash_command_key` (= its manifest_key). */
2153
- readonly key: string;
2154
- /** Reserved: a future confirm step before dispatch (manifest `requiresConfirmation`). */
2155
- readonly requiresConfirmation?: boolean;
2156
- /** Parameter sources resolved into `system_context` at dispatch. */
2157
- readonly contextBindings?: readonly AgentCommandContextBinding[];
2158
- }
2159
- /** What hosts pass to {@link AgentCommandRegistry.register}. Adds the scope to {@link AgentCommand}. */
2160
- interface AgentCommandRegistration extends AgentCommand {
2161
- readonly scope: AgentCommandScope;
2358
+ interface EntityLinkSelection {
2359
+ /** The entity's display title the link's visible text. */
2360
+ readonly label: string;
2361
+ /** Dotted `<appId>.<entity>` kind token (the `flyos:` host segment). */
2362
+ readonly kind: string;
2363
+ /** The entity id. */
2364
+ readonly id: string;
2365
+ /** Owning app id. */
2366
+ readonly appId: string;
2367
+ /** Resolved in-app route, e.g. `/trends/<id>`. */
2368
+ readonly route: string;
2369
+ /** Full `flyos:<appId>.<entity>/<id>` deep-link href. */
2370
+ readonly href: string;
2162
2371
  }
2163
- /** Disposable handle returned by {@link AgentCommandRegistry.register}. Idempotent `dispose()`. */
2164
- interface AgentCommandHandle {
2165
- dispose(): void;
2372
+
2373
+ /**
2374
+ * Shared floating entity typeahead — the `/lookup` picker promoted out of the
2375
+ * agent composer into the design-system so any app (agent composer, notes,
2376
+ * task comments, federated remotes) can let a user find an entity and act on
2377
+ * it. Editor-agnostic: it emits a {@link LookupResult} ({@link pick}) and,
2378
+ * when the entity resolves to a deep link, an {@link EntityLinkSelection}
2379
+ * ({@link entityLinkSelected}) — the consumer decides whether to make a ref
2380
+ * chip, insert a `flyos:` link into an editor, etc.
2381
+ *
2382
+ * Two-stage cascade:
2383
+ * - **Stage 1 — entity**: a filterable autocomplete of the offered entities.
2384
+ * Skipped when there's one entity or `initialEntity` already names one.
2385
+ * - **Stage 2 — search**: a debounced typeahead against the chosen entity's
2386
+ * search endpoint, with a breadcrumb back to stage 1.
2387
+ *
2388
+ * The HTTP call goes through the host's `HttpClient` so the gateway routing +
2389
+ * auth interceptor apply — the same path the MCP `*_list_brief` tools wrap,
2390
+ * but user-authenticated. The "exposed by app" badge resolves names via the
2391
+ * optional {@link LOOKUP_APP_NAME_RESOLVER} the host provides (the DS has no
2392
+ * app registry); absent it, the badge falls back to `appBadgeKey`.
2393
+ */
2394
+ declare class EntityLookupComponent implements OnInit, OnDestroy {
2395
+ private readonly http;
2396
+ private readonly i18n;
2397
+ private readonly host;
2398
+ private readonly lookupRegistry;
2399
+ /** Host-provided appId → {id,name} adapter for the "exposed by app" badge.
2400
+ * The DS has no app registry; the shell (and remotes) provide APP_LOOKUP.
2401
+ * Optional — absent, the badge falls back to a descriptor's appBadgeKey. */
2402
+ private readonly appLookup;
2403
+ /** Entities the picker may search — already filtered to the live-app scope
2404
+ * by the caller. Empty renders a "nothing to look up" hint. */
2405
+ readonly descriptors: _angular_core.InputSignal<readonly LookupDescriptor[]>;
2406
+ /** Entity pre-selected (e.g. from `/lookup <entity>`). Ignored when it
2407
+ * doesn't match any descriptor (falls back to the first). */
2408
+ readonly initialEntity: _angular_core.InputSignal<string | undefined>;
2409
+ /** Query text pre-seeded (e.g. from `/lookup <entity> <query>`). */
2410
+ readonly initialQuery: _angular_core.InputSignal<string>;
2411
+ /** Per-instance listbox id so `aria-controls` / `aria-activedescendant`
2412
+ * resolve unambiguously when multiple panels mount. */
2413
+ readonly listboxId: _angular_core.InputSignal<string>;
2414
+ /** Open direction. `'up'` (default) suits a bottom-anchored composer (the
2415
+ * agent input); `'down'` suits a top-anchored toolbar button (notes / task
2416
+ * comments) — the panel then anchors to the host's positioned parent (the
2417
+ * button wrapper) and opens below it with a fixed width. */
2418
+ readonly placement: _angular_core.InputSignal<"up" | "down" | "above">;
2419
+ /** Raw pick — every consumer gets this (agent ref chips, etc.). */
2420
+ readonly pick: _angular_core.OutputEmitterRef<LookupResult>;
2421
+ /** Deep-link selection — emitted ONLY when the picked entity resolves to a
2422
+ * route via the lookup registry (so the consumer never gets a dead link).
2423
+ * Editors bind this to insert a `flyos:` anchor. */
2424
+ readonly entityLinkSelected: _angular_core.OutputEmitterRef<EntityLinkSelection>;
2425
+ readonly dismiss: _angular_core.OutputEmitterRef<void>;
2426
+ /** Which cascade stage is active: pick an entity, then search within it. */
2427
+ readonly stage: _angular_core.WritableSignal<"search" | "entity">;
2428
+ /** entity key of the descriptor currently being searched. */
2429
+ readonly activeEntity: _angular_core.WritableSignal<string | null>;
2430
+ /** In stage 1 this filters the entity list; in stage 2 it's the search text. */
2431
+ readonly query: _angular_core.WritableSignal<string>;
2432
+ readonly results: _angular_core.WritableSignal<readonly LookupResult[]>;
2433
+ readonly loading: _angular_core.WritableSignal<boolean>;
2434
+ /** i18n key for an inline error (network / bad endpoint); null when clear. */
2435
+ readonly errorKey: _angular_core.WritableSignal<string | null>;
2436
+ readonly activeIndex: _angular_core.WritableSignal<number>;
2437
+ /** Query stashed when no entity matched, so it can seed the search field the
2438
+ * moment the user picks an entity. One-shot. */
2439
+ private _seedQuery;
2440
+ /** The descriptor matching {@link activeEntity}, or null. */
2441
+ readonly activeDescriptor: _angular_core.Signal<LookupDescriptor | null>;
2442
+ /** Stage-1 entity options, narrowed by the typed filter. Touches
2443
+ * `i18n.version()` so a locale switch re-resolves the label match. */
2444
+ readonly filteredEntities: _angular_core.Signal<readonly LookupDescriptor[]>;
2445
+ /** Size of the list the keyboard currently navigates (entities vs results). */
2446
+ readonly listSize: _angular_core.Signal<number>;
2447
+ /** Show the breadcrumb / back affordance only when there's a real choice of
2448
+ * entity to step back to. */
2449
+ readonly showBack: _angular_core.Signal<boolean>;
2450
+ /** Placeholder reflects the active stage. */
2451
+ readonly searchPlaceholderKey: _angular_core.Signal<string>;
2452
+ private _debounceTimer;
2453
+ private _searchSub;
2454
+ private readonly searchEl?;
2455
+ constructor();
2456
+ ngOnInit(): void;
2457
+ ngOnDestroy(): void;
2458
+ optionId(index: number): string;
2459
+ readonly activeDescendant: _angular_core.Signal<string>;
2460
+ private _clampedIndex;
2461
+ onQueryInput(value: string): void;
2462
+ onSelectEntity(entity: string): void;
2463
+ goBackToEntity(): void;
2464
+ onRowClick(row: LookupResult): void;
2465
+ onRowHover(index: number): void;
2466
+ /**
2467
+ * Single pick exit. Emits the raw {@link pick} for every consumer, AND —
2468
+ * when the entity resolves to a deep-link route via the registry — an
2469
+ * {@link entityLinkSelected} carrying the `flyos:` href. Resolution failures
2470
+ * (unknown entity / app mismatch / owning app not installed / no
2471
+ * `deepLinkRoute`) simply omit the deep-link event: editor consumers get
2472
+ * nothing to insert rather than a dead link, while the raw `pick` path
2473
+ * (agent ref chips) still fires.
2474
+ */
2475
+ private _selectRow;
2476
+ onKeydown(ev: KeyboardEvent): void;
2477
+ onDocumentMouseDown(ev: MouseEvent): void;
2478
+ onDocumentEscape(): void;
2479
+ private _scheduleSearch;
2480
+ private _clearTimer;
2481
+ private _runSearch;
2482
+ private _mapResults;
2483
+ private _extractArray;
2484
+ private _focusSearch;
2485
+ entityLabel(desc: LookupDescriptor): string;
2486
+ readonly activeEntityLabel: _angular_core.Signal<string>;
2487
+ /**
2488
+ * Display name of the app exposing this descriptor, for the "exposed by …"
2489
+ * badge. Resolution order: host-provided {@link LOOKUP_APP_NAME_RESOLVER}
2490
+ * (keyed by `descriptor.appId`) → descriptor `appBadgeKey` (literal i18n
2491
+ * key, for entities not mapped to a single shell app) → '' (no badge).
2492
+ */
2493
+ appLabel(desc: LookupDescriptor): string;
2494
+ readonly activeAppLabel: _angular_core.Signal<string>;
2495
+ /** Per-row source-app label for stage-2 rows. Resolves {@link LookupResult.appId}
2496
+ * through the host resolver. '' when the row carries no `appId`, the resolver
2497
+ * is absent / doesn't know it, or it duplicates {@link activeAppLabel}. */
2498
+ rowAppLabel(row: LookupResult): string;
2499
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<EntityLookupComponent, never>;
2500
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<EntityLookupComponent, "fly-entity-lookup", never, { "descriptors": { "alias": "descriptors"; "required": true; "isSignal": true; }; "initialEntity": { "alias": "initialEntity"; "required": false; "isSignal": true; }; "initialQuery": { "alias": "initialQuery"; "required": false; "isSignal": true; }; "listboxId": { "alias": "listboxId"; "required": false; "isSignal": true; }; "placement": { "alias": "placement"; "required": false; "isSignal": true; }; }, { "pick": "pick"; "entityLinkSelected": "entityLinkSelected"; "dismiss": "dismiss"; }, never, never, true, never>;
2166
2501
  }
2502
+
2167
2503
  /**
2168
- * How a lookup fetches candidate entities. The picker calls the app's existing
2169
- * authenticated REST search endpoint (the same one the agent's MCP `*_list_brief`
2170
- * tool wraps) through the shell's HttpClient — gateway routing + auth
2171
- * interceptor apply. We deliberately do NOT route typeahead through MCP (agent-
2172
- * shaped, agent-auth) or the dataset executor (aggregation-shaped, no fulltext).
2504
+ * Host-provided handler that navigates to a resolved in-app entity deep link
2505
+ * when the user clicks a `flyos:` anchor inside a {@link FlyMarkdownEditorComponent}.
2173
2506
  *
2174
- * Field mapping is declarative because entities differ: Circles trends/signals
2175
- * expose `/brief` endpoints returning `{ id, title, status }`, while scenarios
2176
- * have no brief variant and return full objects with `titleEn` / `titleAr`. The
2177
- * `displayField` / `secondaryField` indirection absorbs that per-entity skew so
2178
- * one picker component serves them all.
2507
+ * The design-system can RESOLVE a `flyos:<appId>.<entity>/<id>` href to a
2508
+ * `{ appId, route }` (via `AgentLookupRegistry`), but it cannot LAUNCH it — the
2509
+ * launcher lives in the host (the desktop shell's `ShellLauncherService`, or a
2510
+ * remote's own router). The host provides this token; when absent, a `flyos:`
2511
+ * click is a no-op (the link is non-routable in a bare browser anyway).
2179
2512
  */
2180
- interface LookupSearch {
2181
- /**
2182
- * Relative REST path the picker GETs, e.g. `/api/circles/trends/brief`. Must
2183
- * be a relative path (no scheme/host) — the SSRF guard at onboard time (when
2184
- * the descriptor is manifest-backed) and the picker both reject absolute URLs.
2185
- */
2186
- readonly endpoint: string;
2187
- /** Query param carrying the typed text, e.g. `search`. */
2188
- readonly queryParam: string;
2189
- /** Static query params merged into every request, e.g. `{ pageSize: '10' }`. */
2190
- readonly extraParams?: Readonly<Record<string, string>>;
2191
- /** Response-item field holding the entity id. Default `id`. */
2192
- readonly idField?: string;
2193
- /** Response-item field holding the display label, e.g. `title` / `titleEn`. */
2194
- readonly displayField: string;
2195
- /** Optional response-item field for the chip's secondary line (status, category). */
2196
- readonly secondaryField?: string;
2197
- /**
2198
- * Optional response-item field whose value is a *row-level* app id — i.e. the
2199
- * app that owns this individual entity, distinct from the descriptor's
2200
- * {@link LookupDescriptor.appId} (which only names the app exposing the
2201
- * lookup endpoint). Help articles are the motivating case: every article is
2202
- * exposed by `help-center`, but each one was seeded by a *source* app's
2203
- * manifest (Circles, Trends, …). Surfacing that per-row appId lets the
2204
- * picker render a second source-app tag so the user can tell two
2205
- * similarly-titled rows from different source apps apart at a glance.
2206
- *
2207
- * Resolved through {@link LookupResult.appId} and the shell's app registry
2208
- * with the same fallback chain used for {@link LookupDescriptor.appId}.
2209
- */
2210
- readonly appIdField?: string;
2211
- /**
2212
- * Dotted path to the results array within the response body when it is
2213
- * wrapped, e.g. `items` for `{ items: [...], total }`. Omit when the response
2214
- * body IS the array.
2215
- */
2216
- readonly resultsPath?: string;
2217
- }
2513
+ type EntityLinkLauncher = (target: {
2514
+ readonly appId: string;
2515
+ readonly route: string;
2516
+ readonly kind: string;
2517
+ readonly id: string;
2518
+ }) => void;
2519
+ declare const ENTITY_LINK_LAUNCHER: InjectionToken<EntityLinkLauncher>;
2218
2520
  /**
2219
- * A lookupable entity offered by the `/lookup` palette. Registered by the owning
2220
- * app (a federation remote self-registers at boot, mirroring {@link AgentCommand})
2221
- * or, once manifest-backed, projected from the app's `lookups[]` manifest section.
2222
- *
2223
- * The descriptor is a shallow, business-logic-free descriptor: it tells the
2224
- * picker WHAT to search, WHERE it is offered, and HOW to map the response — the
2225
- * picker owns the typeahead UX, the shell owns the HTTP call.
2521
+ * A toolbar control id, or `'|'` for a visual divider. `toolbar` accepts a
2522
+ * preset name or an explicit ordered list of these.
2226
2523
  */
2227
- interface LookupDescriptor {
2228
- /**
2229
- * Stable entity key, kebab/lower, e.g. `scenario`. Doubles as the `/lookup
2230
- * <entity>` sub-token and the group key the picked ref is grouped under when
2231
- * serialized for the agent.
2232
- */
2233
- readonly entity: string;
2234
- /** i18n key for the entity's display name in the picker / palette. */
2235
- readonly labelKey: string;
2236
- /** Optional PrimeIcons class for the picker row + chip. */
2237
- readonly icon?: string;
2238
- /**
2239
- * Stable id of the app that exposes this lookup, e.g. `notes`, `calendar`,
2240
- * `circles`. The picker resolves it to the app's display name via the shell's
2241
- * app registry and renders an "exposed by …" badge so the user can see which
2242
- * app owns the entity they're browsing (helps disambiguate when two apps
2243
- * register a similar-sounding entity, e.g. both Tasks and Notes one day).
2244
- *
2245
- * Populated automatically by the shell's registration paths:
2246
- * - `CORE_APP_LOOKUPS` stamps it per descriptor at hand-edit time.
2247
- * - `RemoteManifestService` stamps it from the manifest entry's `id` so
2248
- * federation remotes don't have to repeat the id in every descriptor.
2249
- *
2250
- * Falls back to {@link appBadgeKey} (a locale-resolved literal) when an
2251
- * entity has no first-class home in the shell's app registry — e.g. `user`,
2252
- * `app-agent`, `robot`. When neither is set the picker omits the badge.
2253
- */
2254
- readonly appId?: string;
2255
- /**
2256
- * Optional i18n key the picker uses for the "exposed by …" badge **when
2257
- * {@link appId} is absent or unknown to the shell's app registry**. Lets
2258
- * entities that don't map to a single app (Users, Robots, App Agents) still
2259
- * surface a meaningful badge instead of silently omitting it. The picker
2260
- * resolves the key via the shared i18n service so the badge follows the
2261
- * user's locale.
2262
- */
2263
- readonly appBadgeKey?: string;
2264
- /**
2265
- * Advisory MCP tool-key prefixes the agent should prefer when the user
2266
- * references this entity via `/lookup` (e.g. `['dashboard.reports']`). The
2267
- * shell folds these into the turn's `mcp_scope` so the Twin self-serves the
2268
- * owning app's tools — fetching and analysing the referenced entity itself —
2269
- * instead of defaulting to a specialist-Robot consult for "tell me more"
2270
- * style prompts. Same dot-namespaced prefix vocabulary as
2271
- * {@link AgentMcpScope.apis}. Omit for entities with no first-class MCP tool
2272
- * family (e.g. `user`, `robot`).
2273
- */
2274
- readonly mcpApis?: readonly string[];
2275
- /**
2276
- * Optional in-app deep-link route TEMPLATE for this entity's detail page,
2277
- * e.g. `'/signals/{id}'`. When present, the desktop shell turns an agent's
2278
- * inline reference to this entity — the `flyos:<appId>.<entity>/<id>`
2279
- * anchors the agents backend emits in chat answers — into a launchable
2280
- * link: the single `{id}` placeholder is substituted with the referenced
2281
- * entity's id (URL-encoded) and the owning {@link appId} is launched on
2282
- * that route via the shell launcher.
2283
- *
2284
- * Omit for entities with no standalone detail page — their references then
2285
- * render as plain text (graceful degrade; never a dead link). The owning
2286
- * app declares this once in its `lookups[]` manifest entry, so a remote
2287
- * becomes agent-deep-linkable without any shell or design-system change.
2288
- * Only `{id}` is substituted here — richer parameterisation rides the
2289
- * deep-link `params` channel, not this template.
2290
- */
2291
- readonly deepLinkRoute?: string;
2292
- /** How to fetch + map candidates. */
2293
- readonly search: LookupSearch;
2524
+ type MarkdownToolbarItem = 'undo' | 'redo' | 'h1' | 'h2' | 'h3' | 'bold' | 'italic' | 'underline' | 'strike' | 'code' | 'bulletList' | 'orderedList' | 'taskList' | 'blockquote' | 'codeBlock' | 'horizontalRule' | 'link' | 'entityLink' | '|';
2525
+ /** Named toolbar presets. `full` ≈ the notes editor; `compact` ≈ task comments. */
2526
+ type MarkdownToolbarPreset = 'full' | 'compact';
2527
+ declare const MARKDOWN_TOOLBAR_PRESETS: Record<MarkdownToolbarPreset, readonly MarkdownToolbarItem[]>;
2528
+
2529
+ /**
2530
+ * Shared rich-text/markdown editor — the single Tiptap-backed editor for FlyOS
2531
+ * apps (notes, task comments, admin) and Business Apps (Circles). Emits a
2532
+ * Markdown string via `ControlValueAccessor`, so it slots into reactive forms
2533
+ * or `[(ngModel)]` with no orchestration.
2534
+ *
2535
+ * Bakes in the platform's `flyos:` entity-deep-link contract: the Link mark
2536
+ * whitelists the `flyos` scheme (so authored/pasted deep links aren't blanked),
2537
+ * clicks on a resolvable `flyos:` anchor launch the owning app via the
2538
+ * host-provided {@link ENTITY_LINK_LAUNCHER}, and the optional "entity link"
2539
+ * toolbar button opens the shared {@link EntityLookupComponent} to insert one.
2540
+ */
2541
+ declare class FlyMarkdownEditorComponent implements ControlValueAccessor, OnDestroy {
2542
+ private readonly cdr;
2543
+ private readonly lookupRegistry;
2544
+ private readonly launcher;
2545
+ /** Toolbar preset name or an explicit ordered item list. */
2546
+ readonly toolbar: _angular_core.InputSignal<MarkdownToolbarPreset | readonly MarkdownToolbarItem[]>;
2547
+ /** Show the "insert in-app link" (entity-lookup) toolbar button. */
2548
+ readonly enableEntityLink: _angular_core.InputSignal<boolean>;
2549
+ /** Direction the entity-lookup dropdown opens. `down` (default) suits a
2550
+ * top toolbar (notes); `above` suits a bottom-anchored composer (task
2551
+ * comments) so the panel doesn't run off the viewport. */
2552
+ readonly entityLinkPlacement: _angular_core.InputSignal<"down" | "above">;
2553
+ readonly placeholder: _angular_core.InputSignal<string>;
2554
+ readonly readonly: _angular_core.InputSignal<boolean>;
2555
+ readonly ariaLabel: _angular_core.InputSignal<string>;
2556
+ /** Fired on Ctrl/Cmd+Enter (host can submit a comment, etc.). */
2557
+ readonly submitShortcut: _angular_core.OutputEmitterRef<void>;
2558
+ private onChange;
2559
+ private onTouched;
2560
+ private currentValue;
2561
+ readonly activeStates: _angular_core.WritableSignal<Record<string, boolean>>;
2562
+ readonly canUndo: _angular_core.WritableSignal<boolean>;
2563
+ readonly canRedo: _angular_core.WritableSignal<boolean>;
2564
+ readonly showLinkPopover: _angular_core.WritableSignal<boolean>;
2565
+ readonly linkInputValue: _angular_core.WritableSignal<string>;
2566
+ readonly showEntityLookup: _angular_core.WritableSignal<boolean>;
2567
+ readonly entityLookupDescriptors: _angular_core.Signal<readonly LookupDescriptor[]>;
2568
+ /** Resolved toolbar items (preset array), entityLink stripped when disabled. */
2569
+ readonly toolbarItems: _angular_core.Signal<readonly MarkdownToolbarItem[]>;
2570
+ readonly editor: Editor;
2571
+ constructor();
2572
+ ngOnDestroy(): void;
2573
+ writeValue(value: string | null): void;
2574
+ registerOnChange(fn: (v: string) => void): void;
2575
+ registerOnTouched(fn: () => void): void;
2576
+ setDisabledState(isDisabled: boolean): void;
2577
+ /** Current markdown (same as the CVA value). */
2578
+ getMarkdown(): string;
2579
+ /** Current rendered HTML snapshot. */
2580
+ getHtml(): string;
2581
+ /** Focus the editor surface. */
2582
+ focus(): void;
2583
+ button(id: MarkdownToolbarItem): {
2584
+ icon: string;
2585
+ labelKey: string;
2586
+ } | null;
2587
+ /** Short visual label for buttons rendered as text (B / I / U / S / H1…). */
2588
+ textLabel(id: MarkdownToolbarItem): string | null;
2589
+ run(id: MarkdownToolbarItem): void;
2590
+ isActive(id: MarkdownToolbarItem): boolean;
2591
+ disabled(id: MarkdownToolbarItem): boolean;
2592
+ private refreshState;
2593
+ openLinkPopover(): void;
2594
+ onLinkInput(value: string): void;
2595
+ commitLink(): void;
2596
+ cancelLink(): void;
2597
+ onLinkKeydown(event: KeyboardEvent): void;
2598
+ toggleEntityLookup(): void;
2599
+ closeEntityLookup(): void;
2600
+ onEntityLinkSelected(sel: EntityLinkSelection): void;
2601
+ /** True (click handled) when a resolvable `flyos:` anchor was launched. */
2602
+ private handleFlyosClick;
2603
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<FlyMarkdownEditorComponent, never>;
2604
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<FlyMarkdownEditorComponent, "fly-markdown-editor", never, { "toolbar": { "alias": "toolbar"; "required": false; "isSignal": true; }; "enableEntityLink": { "alias": "enableEntityLink"; "required": false; "isSignal": true; }; "entityLinkPlacement": { "alias": "entityLinkPlacement"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; }, { "submitShortcut": "submitShortcut"; }, never, never, true, never>;
2294
2605
  }
2295
- /** What hosts pass to the lookup registry. Adds the scope to {@link LookupDescriptor}. */
2296
- interface LookupRegistration extends LookupDescriptor {
2297
- /**
2298
- * Affinity hint, NOT a visibility gate.
2299
- *
2300
- * Unlike {@link AgentCommandScope} — where `{appId}` HIDES a command unless the
2301
- * app is live — lookup scope is a *priority hint*. Every registered lookup is
2302
- * always offered in `/lookup`; when the app named by `{appId}` is in the host's
2303
- * live app set, that lookup sorts to the **top** of the entity picker so the
2304
- * "what am I working on right now?" entities surface first. `'global'` lookups
2305
- * have no affinity and sort after app-affinity matches.
2306
- *
2307
- * Rationale: OS-core entities (note, calendar event, file) are always
2308
- * referenceable — there's no "open the app first" condition the way there is
2309
- * for federated remotes — so a visibility gate would just produce a confusing
2310
- * empty state. Affinity-as-sort preserves the "Circles is open → prefer
2311
- * scenarios/trends/signals" intuition without hiding the rest.
2312
- */
2313
- readonly scope: AgentCommandScope;
2606
+
2607
+ interface ContextMenuItem {
2608
+ id: string;
2609
+ label: string;
2610
+ icon: string;
2611
+ }
2612
+ interface ContextMenuSection {
2613
+ label?: string;
2614
+ items: ContextMenuItem[];
2615
+ }
2616
+ declare class ContextMenuComponent implements AfterViewInit, OnDestroy {
2617
+ private menuEl?;
2618
+ private readonly doc;
2619
+ private readonly hostEl;
2620
+ x: _angular_core.InputSignal<number>;
2621
+ y: _angular_core.InputSignal<number>;
2622
+ sections: _angular_core.InputSignal<ContextMenuSection[]>;
2623
+ action: _angular_core.OutputEmitterRef<string>;
2624
+ closed: _angular_core.OutputEmitterRef<void>;
2625
+ private menuWidth;
2626
+ private menuHeight;
2627
+ private previouslyFocused;
2628
+ clampedPos: _angular_core.Signal<{
2629
+ left: number;
2630
+ top: number;
2631
+ }>;
2632
+ ngAfterViewInit(): void;
2633
+ ngOnDestroy(): void;
2634
+ onAction(id: string): void;
2635
+ onClickOutside(event: MouseEvent): void;
2636
+ onEscape(): void;
2637
+ onContextMenu(event: MouseEvent): void;
2638
+ onKeydown(event: KeyboardEvent): void;
2639
+ private close;
2640
+ private getMenuItems;
2641
+ private focusItem;
2642
+ private restoreFocus;
2643
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<ContextMenuComponent, never>;
2644
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<ContextMenuComponent, "fly-context-menu", never, { "x": { "alias": "x"; "required": true; "isSignal": true; }; "y": { "alias": "y"; "required": true; "isSignal": true; }; "sections": { "alias": "sections"; "required": true; "isSignal": true; }; }, { "action": "action"; "closed": "closed"; }, never, never, true, never>;
2645
+ }
2646
+
2647
+ declare enum MessageBoxButtons {
2648
+ OK = 0,
2649
+ OKCancel = 1,
2650
+ YesNo = 2,
2651
+ YesNoCancel = 3,
2652
+ RetryCancel = 4,
2653
+ AbortRetryIgnore = 5
2654
+ }
2655
+ declare enum MessageBoxIcon {
2656
+ None = 0,
2657
+ Information = 1,
2658
+ Warning = 2,
2659
+ Error = 3,
2660
+ Question = 4
2314
2661
  }
2315
- /** One resolved row the picker returns once the user selects a candidate. */
2316
- interface LookupResult {
2317
- /** The entity kind (echoes {@link LookupDescriptor.entity}). */
2318
- readonly entity: string;
2319
- /** Selected entity id. */
2320
- readonly id: string;
2321
- /** Selected entity's display label. */
2322
- readonly label: string;
2323
- /** Optional secondary detail (status / category). */
2324
- readonly secondary?: string;
2325
- /**
2326
- * Row-level source app id (e.g. `circles` for an article seeded by Circles'
2327
- * manifest). Populated when the descriptor sets {@link LookupSearch.appIdField}
2328
- * and the response item carries a non-empty value. The picker renders it as
2329
- * a second app tag alongside the descriptor-level badge so the user can see
2330
- * "this Help-Center article was contributed by Circles" without opening it.
2331
- */
2332
- readonly appId?: string;
2662
+ declare enum DialogResult {
2663
+ None = 0,
2664
+ OK = 1,
2665
+ Cancel = 2,
2666
+ Yes = 3,
2667
+ No = 4,
2668
+ Retry = 5,
2669
+ Abort = 6,
2670
+ Ignore = 7
2333
2671
  }
2334
- /** Disposable handle returned by the lookup registry. Idempotent `dispose()`. */
2335
- interface LookupHandle {
2336
- dispose(): void;
2672
+ interface MessageBoxOptions {
2673
+ title: string;
2674
+ message: string;
2675
+ buttons?: MessageBoxButtons;
2676
+ icon?: MessageBoxIcon;
2337
2677
  }
2338
2678
  /**
2339
- * The wire envelope used by both the drag/drop surface and the imperative
2340
- * {@link AgentActionBus}. Renderers narrow on `kind`; mismatches fall back to
2341
- * `plainTextFallback`.
2342
- *
2343
- * The base fields (v1) describe **what** is being handed to the agent panel.
2344
- * The v2 fields describe **how the agent should treat it** — `userMessage`
2345
- * scopes the user-visible bubble, `systemContext` extends the system prompt,
2346
- * `attachments` decorate the message with typed chips, and `mcpScope` hints
2347
- * the agent toward a tool family. All v2 fields are optional so existing
2348
- * v1 (drag/drop) payloads remain valid envelopes.
2349
- *
2350
- * Caps (see {@link AgentPayloadLimits}):
2351
- * - JSON total 32 KB
2352
- * - plainTextFallback 8 KB
2353
- * - per-string field 4 KB
2354
- * - userMessage 280 chars
2355
- * - systemContext 32 entries × 4 KB per value, 8 KB total serialized
2356
- * - attachments 4 entries, kind-dependent inner caps
2357
- * - mcpScope.apis 5 prefixes × 128 chars
2358
- *
2359
- * The cap math is split per-section so an oversize attachment fails fast at the
2360
- * attachment site instead of the whole envelope; field paths are dotted (see
2361
- * {@link AgentPayloadValidationResult}).
2679
+ * Configuration for the "Don't ask again" checkbox rendered by
2680
+ * `showAcknowledged()`. The field is intentionally NOT part of the base
2681
+ * `MessageBoxOptions` so the type system enforces the rule
2682
+ * "checkbox ⇒ caller MUST use `showAcknowledged()`": the classic `show()`
2683
+ * entry point cannot accept this shape, eliminating the silent-discard
2684
+ * dark-pattern path where the user's choice was thrown away.
2362
2685
  */
2363
- interface AgentDragPayload<T = unknown> {
2364
- /** Domain-stable kind, e.g. `circles.trend`. */
2365
- readonly kind: string;
2366
- /** Originating appId. Must match an entry in the host's app registry. */
2367
- readonly appId: string;
2368
- /** Frozen format version. Accepted: 1 or {@link AGENT_PAYLOAD_VERSION} (2). */
2369
- readonly version: number;
2370
- /** Domain object. Renderers narrow on `kind`. */
2371
- readonly payload: T;
2372
- /** Plain-text fallback written to the dataTransfer alongside the typed MIME. */
2373
- readonly plainTextFallback: string;
2374
- /** Optional command ids to highlight when this payload is dropped. */
2375
- readonly suggestedCommandIds?: readonly string[];
2376
- /**
2377
- * Short, locale-resolved string the dispatcher wants shown in the user's
2378
- * chat bubble. The agent panel uses it as the visible message text; when
2379
- * absent, the panel falls back to a generic per-verb default
2380
- * (e.g. "Tell me more about this"). Cap 280 chars — chip-sized, not essay.
2381
- *
2382
- * This is the ONLY field that should ever surface to the user verbatim.
2383
- * Everything else (systemContext, attachment bodies, mcpScope) is wire-only.
2384
- */
2385
- readonly userMessage?: string;
2386
- /**
2387
- * Flat key→string facts the dispatcher wants injected into the agent's
2388
- * system prompt for this turn. Keys are dot-namespaced (e.g.
2389
- * `chart.name`, `chart.type`, `chart.dimension`) to keep the model's
2390
- * mental schema flat and grep-friendly. Values are strings — booleans,
2391
- * numbers, and dates must be pre-serialized at the call site so the
2392
- * dispatcher owns the formatting (timezone, locale, number style).
2393
- *
2394
- * Cap: 32 entries, 4 KB per value, 8 KB total when serialized.
2395
- *
2396
- * NOT user-visible. The agent panel may transiently embed this as an
2397
- * `[Internal context]` block in the wire content while the backend
2398
- * learns to consume the dedicated field, but never renders it in the
2399
- * user bubble.
2400
- */
2401
- readonly systemContext?: Readonly<Record<string, string>>;
2686
+ interface MessageBoxDontAskAgainConfig {
2687
+ /** i18n key for the checkbox label, e.g. 'agent.command.builtin.clear.dont_ask_again'. */
2688
+ labelKey: string;
2689
+ /** Initial checked state. Default false. */
2690
+ defaultChecked?: boolean;
2691
+ }
2692
+ /**
2693
+ * Options narrowed to those carrying a `dontAskAgain` config — the only shape
2694
+ * accepted by `showAcknowledged()`.
2695
+ */
2696
+ interface MessageBoxOptionsWithAcknowledgement extends MessageBoxOptions {
2697
+ dontAskAgain: MessageBoxDontAskAgainConfig;
2698
+ }
2699
+ interface MessageBoxButton {
2700
+ label: string;
2701
+ result: DialogResult;
2702
+ variant?: 'primary' | 'danger' | 'default';
2703
+ }
2704
+ /** Shape returned by `showAcknowledged()` — pairs the dialog result with the checkbox state. */
2705
+ interface DialogResultWithAcknowledgement {
2706
+ readonly result: DialogResult;
2707
+ readonly dontAskAgain: boolean;
2708
+ }
2709
+ declare class MessageBoxService {
2710
+ private readonly i18n;
2711
+ readonly visible: _angular_core.WritableSignal<boolean>;
2712
+ readonly title: _angular_core.WritableSignal<string>;
2713
+ readonly message: _angular_core.WritableSignal<string>;
2714
+ readonly icon: _angular_core.WritableSignal<MessageBoxIcon>;
2715
+ readonly buttons: _angular_core.WritableSignal<MessageBoxButton[]>;
2402
2716
  /**
2403
- * Typed attachments rendered as a chip strip under the user's outgoing
2404
- * message bubble. Each entry has a `kind` discriminator and a `label`
2405
- * (locale-resolved by the dispatcher). v2 ships `json` + `text`;
2406
- * `image` and `file` are reserved — their interfaces are stable so
2407
- * future callers don't need a contract bump, but the panel may render
2408
- * a generic chip for them until per-kind renderers land.
2409
- *
2410
- * Cap: 4 entries per envelope. Per-kind body caps:
2411
- * - json: 16 KB serialized
2412
- * - text: 8 KB UTF-8
2413
- * - image / file: dataUrl ≤ 32 KB (small previews; large media stays in
2414
- * the files-manager and is referenced by id)
2717
+ * Active "Don't ask again" config populated only by `showAcknowledged()`.
2718
+ * `show()` callers cannot reach this signal because the type system rejects
2719
+ * `dontAskAgain` on the base `MessageBoxOptions`.
2415
2720
  */
2416
- readonly attachments?: readonly AgentEnvelopeAttachment[];
2721
+ readonly dontAskAgain: _angular_core.WritableSignal<MessageBoxDontAskAgainConfig | undefined>;
2417
2722
  /**
2418
- * Advisory MCP scope. The agent service injects these prefixes into the
2419
- * system prompt as a tool-selection hint ("prefer tools matching
2420
- * `dashboard.reports.*` for this turn") NOT a hard filter. The agent
2421
- * remains free to pick any tool; this just biases the first guess so a
2422
- * dashboard explain doesn't waste a tool-call probing Notes APIs first.
2423
- *
2424
- * Cap: 5 prefixes × 128 chars. Prefixes should match gateway-aggregated
2425
- * OpenAPI tag/path roots so they line up with the names the MCP server
2426
- * exposes — see `src/backend/gateway` Swagger aggregation + the dynamic
2427
- * loader in `src/backend/mcp-server`.
2723
+ * Component-side checkbox state. The component (`MessageBoxComponent`) wires
2724
+ * its own signal to this one; the service explicitly re-seeds it on every
2725
+ * `_open()` so reusing a constant `options` literal across two opens does
2726
+ * NOT leak the previous user's checkbox state through signal `===` dedupe.
2727
+ * Exposed for the component to read/write; not for general callers.
2428
2728
  */
2429
- readonly mcpScope?: AgentMcpScope;
2729
+ readonly dontAskAgainChecked: _angular_core.WritableSignal<boolean>;
2730
+ private resolver;
2731
+ show(options: MessageBoxOptions): Promise<DialogResult>;
2430
2732
  /**
2431
- * Optional deep-link route the originating app can use to re-open the
2432
- * source object. When set, payload chips (and any other renderer that
2433
- * surfaces the envelope to the user) become clickable clicking calls
2434
- * `ShellLauncherService.launch({ appId, route: deepLinkRoute })` so the
2435
- * target app opens / focuses and navigates to the originating object.
2436
- *
2437
- * Shape constraints (mirror `DeepLinkService.isValidRoute`):
2438
- * - starts with `/`
2439
- * - ≤ {@link AgentPayloadLimits.maxDeepLinkRouteBytes} bytes (default
2440
- * 1024) — matches the route limit on the wider shell deep-link
2441
- * contract so this field can be handed straight to the launcher.
2442
- * - no `..` segments
2443
- * - no `//` runs
2444
- * - no scheme-like prefixes (`/javascript:`, `/data:`, `/http:`, `/https:`)
2445
- *
2446
- * The DS validator enforces only the byte cap — full route syntax
2447
- * validation is owned by the shell side (`DeepLinkService`) because the
2448
- * DS package is shell-agnostic and shouldn't grow a second copy of the
2449
- * URL grammar. Apps building envelopes are expected to stamp routes that
2450
- * match their own internal route schema (e.g. dashboard publishes
2451
- * `/reports/{id}` and `/custom/{id}`); see `skills/cross-app-deep-linking.md`.
2452
- *
2453
- * Backwards-compat: absent on v1 payloads and on v2 payloads built
2454
- * before this field was added. Persisted JSONB chips without the field
2455
- * remain non-clickable; new chips light up automatically.
2733
+ * Opens a message box with a "Don't ask again" checkbox and resolves to both
2734
+ * the dialog result and the checkbox state. Throws when `options.dontAskAgain`
2735
+ * is missing — the checkbox config is mandatory for this entry point. The
2736
+ * compile-time signature already guarantees presence; the runtime check is
2737
+ * defense-in-depth for callers that bypass the type system via `as never`.
2456
2738
  */
2457
- readonly deepLinkRoute?: string;
2739
+ showAcknowledged(options: MessageBoxOptionsWithAcknowledgement): Promise<DialogResultWithAcknowledgement>;
2740
+ resolve(result: DialogResult, dontAskAgain?: boolean): void;
2741
+ private _open;
2742
+ private resolveButtons;
2743
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<MessageBoxService, never>;
2744
+ static ɵprov: _angular_core.ɵɵInjectableDeclaration<MessageBoxService>;
2458
2745
  }
2459
- /**
2460
- * Canonical name for the bus-side envelope. v2 callers should reference this
2461
- * over {@link AgentDragPayload} for clarity — the underlying shape is
2462
- * identical, but the name signals "this is going to the agent, not to a
2463
- * drop zone." The alias is intentional: one wire shape, two semantic uses.
2464
- */
2465
- type AgentMessageEnvelope<T = unknown> = AgentDragPayload<T>;
2466
- /**
2467
- * Typed attachment discriminator for {@link AgentDragPayload.attachments}.
2468
- *
2469
- * - `json` — structured data the panel renders as a "code-ish" chip the
2470
- * user can expand. Used for chart snapshots, query results, etc.
2471
- * - `text` — short utterance / excerpt with optional MIME. Used when the
2472
- * dispatcher wants the chip to preview a note paragraph, log line,
2473
- * code snippet, etc.
2474
- * - `image` / `file` — reserved. Stable interface; renderers added per
2475
- * downstream caller (the panel may fall back to a generic icon-chip).
2476
- *
2477
- * Every kind carries `label` — that's what shows on the chip face and what
2478
- * a11y trees announce.
2479
- */
2480
- type AgentEnvelopeAttachment = {
2481
- readonly kind: 'json';
2482
- readonly label: string;
2483
- readonly json: unknown;
2484
- } | {
2485
- readonly kind: 'text';
2486
- readonly label: string;
2487
- readonly text: string;
2488
- readonly mimeType?: string;
2489
- } | {
2490
- readonly kind: 'image';
2491
- readonly label: string;
2492
- /** `data:` URL — small previews only. Large media stays in files-manager. */
2493
- readonly dataUrl: string;
2494
- readonly mimeType: string;
2495
- } | {
2496
- readonly kind: 'file';
2497
- readonly label: string;
2498
- readonly dataUrl: string;
2499
- readonly mimeType: string;
2500
- readonly bytes: number;
2501
- };
2502
- /** Advisory tool-selection hint for {@link AgentDragPayload.mcpScope}. */
2503
- interface AgentMcpScope {
2746
+
2747
+ declare class MessageBoxComponent implements AfterViewInit {
2748
+ service: MessageBoxService;
2749
+ private elRef;
2750
+ readonly MessageBoxIcon: typeof MessageBoxIcon;
2751
+ readonly DialogResult: typeof DialogResult;
2752
+ /** Mirror of the service's `dontAskAgain` config so the template can read it directly. */
2753
+ readonly dontAskAgainConfig: _angular_core.Signal<_mohamedatia_fly_design_system.MessageBoxDontAskAgainConfig | undefined>;
2504
2754
  /**
2505
- * Prefixes of gateway-aggregated OpenAPI tags / path roots e.g.
2506
- * `dashboard.reports`, `notes.documents`. The agent service treats these
2507
- * as a soft preference, not a hard filter.
2755
+ * User-driven checkbox state, owned by the service and re-seeded on every
2756
+ * `_open()` so reusing a constant options literal cannot leak prior state.
2508
2757
  */
2509
- readonly apis: readonly string[];
2758
+ readonly dontAskAgainChecked: _angular_core.WritableSignal<boolean>;
2759
+ /**
2760
+ * Concatenated id list for the dialog's `aria-describedby`. Always includes
2761
+ * the message; appends the checkbox label id when the checkbox is rendered
2762
+ * so screen readers announce the checkbox as part of the description.
2763
+ */
2764
+ readonly ariaDescribedBy: _angular_core.Signal<"mb-message mb-dont-ask" | "mb-message">;
2765
+ private previouslyFocused;
2766
+ ngAfterViewInit(): void;
2767
+ onEscape(): void;
2768
+ onBackdropClick(): void;
2769
+ onButtonClick(result: DialogResult): void;
2770
+ onDontAskAgainToggle(ev: Event): void;
2771
+ iconClass(): string;
2772
+ private focusPrimaryButton;
2773
+ private restoreFocus;
2774
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<MessageBoxComponent, never>;
2775
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<MessageBoxComponent, "fly-message-box", never, {}, {}, never, never, true, never>;
2510
2776
  }
2777
+
2778
+ /** Full-bleed loading overlay for window content (shell) or embedded hosts. */
2779
+ declare class FlyBlockUiComponent {
2780
+ /** When false, the overlay is not rendered (host may use @if instead). */
2781
+ active: _angular_core.InputSignal<boolean>;
2782
+ /** i18n key for status text; empty uses `common.loading`. */
2783
+ messageKey: _angular_core.InputSignal<string>;
2784
+ readonly resolvedMessageKey: _angular_core.Signal<string>;
2785
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<FlyBlockUiComponent, never>;
2786
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<FlyBlockUiComponent, "fly-block-ui", never, { "active": { "alias": "active"; "required": true; "isSignal": true; }; "messageKey": { "alias": "messageKey"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
2787
+ }
2788
+
2511
2789
  /**
2512
- * Where a chip is being rendered. `inline` = inside the input chip tray (removable);
2513
- * `message` = embedded in a sent message bubble (not removable).
2514
- */
2515
- type AgentDropChipMode = 'inline' | 'message';
2516
- /**
2517
- * Public input shape for chip-renderer components. Components declare matching
2518
- * `input()` signals; the registry wires them via `NgComponentOutlet`.
2790
+ * Metadata returned by Files Manager after a successful upload or metadata query.
2791
+ * Mirrors the `FileMetadataDto` shape from `GET /api/files/{id}` and `POST /api/files/upload`.
2519
2792
  */
2520
- interface AgentChipHostInputs<T = unknown> {
2521
- payload: AgentDragPayload<T>;
2522
- mode: AgentDropChipMode;
2523
- /** Called when the user clicks the chip's remove control (only in inline mode). */
2524
- onRemove?: () => void;
2793
+ interface FlyFileInfo {
2794
+ id: string;
2795
+ fileName: string;
2796
+ contentType: string;
2797
+ sizeBytes: number;
2798
+ sourceApp: string;
2799
+ sourceEntityType?: string;
2800
+ sourceEntityId?: string;
2801
+ uploadedByUserId?: string;
2802
+ correlationId?: string;
2803
+ isConfirmed: boolean;
2804
+ version: number;
2805
+ scanStatus: string;
2806
+ createdAt: string;
2807
+ folderId?: string;
2808
+ hasErrors: boolean;
2525
2809
  }
2810
+
2526
2811
  /**
2527
- * Keyboard-alternative draggable item. Hosts publish these via
2528
- * {@link AgentDropRegistry.publishDraggables} so the "Attach from app…" menu can offer
2529
- * them when pointer drag isn't available.
2812
+ * Image upload component with built-in cropperjs cropping modal.
2813
+ *
2814
+ * Usage:
2815
+ * ```html
2816
+ * <fly-image-upload
2817
+ * [aspectRatio]="16/9"
2818
+ * [currentImageId]="trend.coverImageId"
2819
+ * sourceApp="circles"
2820
+ * sourceEntityType="trend"
2821
+ * (uploaded)="onImageUploaded($event)"
2822
+ * (removed)="onImageRemoved()"
2823
+ * />
2824
+ * ```
2530
2825
  */
2531
- interface AgentDraggableItem<T = unknown> {
2532
- /** Stable id within its app. Used as a list key in the kbd menu. */
2533
- readonly id: string;
2534
- readonly labelKey: string;
2535
- readonly icon?: string;
2536
- /** Builds the payload the moment the user picks the item. */
2537
- build(): AgentDragPayload<T>;
2826
+ declare class FlyImageUploadComponent {
2827
+ private http;
2828
+ private injector;
2829
+ aspectRatio: _angular_core.InputSignal<number>;
2830
+ maxSizeBytes: _angular_core.InputSignal<number>;
2831
+ currentImageId: _angular_core.InputSignal<string | null>;
2832
+ sourceApp: _angular_core.InputSignal<string>;
2833
+ sourceEntityType: _angular_core.InputSignal<string | null>;
2834
+ sourceEntityId: _angular_core.InputSignal<string | null>;
2835
+ uploaded: _angular_core.OutputEmitterRef<FlyFileInfo>;
2836
+ removed: _angular_core.OutputEmitterRef<void>;
2837
+ uploading: _angular_core.WritableSignal<boolean>;
2838
+ error: _angular_core.WritableSignal<string | null>;
2839
+ showCropper: _angular_core.WritableSignal<boolean>;
2840
+ rawImageUrl: _angular_core.WritableSignal<string>;
2841
+ localBlob: _angular_core.WritableSignal<string | null>;
2842
+ fileInput: _angular_core.Signal<ElementRef<HTMLInputElement> | undefined>;
2843
+ cropImage: _angular_core.Signal<ElementRef<HTMLImageElement> | undefined>;
2844
+ private cropper;
2845
+ private selectedFile;
2846
+ /** Resolved preview URL — uses blob for local uploads, fetches authenticated for existing images */
2847
+ previewUrl: _angular_core.WritableSignal<string | null>;
2848
+ constructor();
2849
+ sizeHint: _angular_core.Signal<string>;
2850
+ triggerFileInput(): void;
2851
+ onDragOver(e: DragEvent): void;
2852
+ onDrop(e: DragEvent): void;
2853
+ onFileSelected(e: Event): void;
2854
+ removeImage(): void;
2855
+ cancelCrop(): void;
2856
+ applyCrop(): void;
2857
+ private processFile;
2858
+ private initCropper;
2859
+ private destroyCropper;
2860
+ private uploadFile;
2861
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<FlyImageUploadComponent, never>;
2862
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<FlyImageUploadComponent, "fly-image-upload", never, { "aspectRatio": { "alias": "aspectRatio"; "required": false; "isSignal": true; }; "maxSizeBytes": { "alias": "maxSizeBytes"; "required": false; "isSignal": true; }; "currentImageId": { "alias": "currentImageId"; "required": false; "isSignal": true; }; "sourceApp": { "alias": "sourceApp"; "required": false; "isSignal": true; }; "sourceEntityType": { "alias": "sourceEntityType"; "required": false; "isSignal": true; }; "sourceEntityId": { "alias": "sourceEntityId"; "required": false; "isSignal": true; }; }, { "uploaded": "uploaded"; "removed": "removed"; }, never, never, true, never>;
2538
2863
  }
2539
- /** Registry input shape for binding a chip-renderer component to a kind+appId pair. */
2540
- interface AgentDropRendererRegistration<T = unknown> {
2541
- readonly kind: string;
2542
- readonly appId: string;
2543
- readonly component: Type<AgentChipHostInputs<T>>;
2864
+
2865
+ interface UploadSlot {
2866
+ file: File;
2867
+ progress: number;
2868
+ status: 'uploading' | 'done' | 'error';
2869
+ info?: FlyFileInfo;
2870
+ error?: string;
2544
2871
  }
2545
2872
  /**
2546
- * Caps applied by {@link validateAgentPayload} / {@link trimAgentPayload}. The defaults
2547
- * trade off "fits comfortably in a single MQ frame" against "covers a richly-populated
2548
- * trend or note card". Hosts may pass a partial override.
2873
+ * Multi-file upload with drag-drop, progress, and validation.
2874
+ *
2875
+ * Usage:
2876
+ * ```html
2877
+ * <fly-file-upload
2878
+ * [maxFiles]="5"
2879
+ * [maxFileSizeBytes]="5242880"
2880
+ * accept=".pdf,.docx,.xlsx"
2881
+ * [(files)]="trend.attachments"
2882
+ * sourceApp="circles"
2883
+ * sourceEntityType="trend"
2884
+ * (filesChanged)="onAttachmentsChanged($event)"
2885
+ * />
2886
+ * ```
2549
2887
  */
2550
- interface AgentPayloadLimits {
2551
- /** Cap on the JSON.stringify(envelope) byte length. Default 32 KB. */
2552
- readonly maxJsonBytes: number;
2553
- /** Cap on the plainTextFallback byte length. Default 8 KB. */
2554
- readonly maxPlainTextFallbackBytes: number;
2555
- /** Cap on any single string field inside payload (recursive). Default 4 KB. */
2556
- readonly maxStringFieldBytes: number;
2557
- /** Cap on `userMessage` UTF-8 byte length. Default 280 chars (~1.1 KB). */
2558
- readonly maxUserMessageBytes: number;
2559
- /** Max entries in `systemContext`. Default 32. */
2560
- readonly maxSystemContextEntries: number;
2561
- /** Cap on any single systemContext value's UTF-8 byte length. Default 4 KB. */
2562
- readonly maxSystemContextValueBytes: number;
2563
- /** Cap on the full JSON.stringify(systemContext). Default 8 KB. */
2564
- readonly maxSystemContextJsonBytes: number;
2565
- /** Max attachments per envelope. Default 4. */
2566
- readonly maxAttachments: number;
2567
- /** Cap on a `json` attachment's serialized body. Default 16 KB. */
2568
- readonly maxAttachmentJsonBytes: number;
2569
- /** Cap on a `text` attachment's body bytes. Default 8 KB. */
2570
- readonly maxAttachmentTextBytes: number;
2571
- /** Cap on an `image` / `file` attachment's dataUrl bytes. Default 32 KB. */
2572
- readonly maxAttachmentDataUrlBytes: number;
2573
- /** Max prefixes in `mcpScope.apis`. Default 5. */
2574
- readonly maxMcpScopeApis: number;
2575
- /** Cap on any single mcpScope prefix string. Default 128 chars. */
2576
- readonly maxMcpScopeApiBytes: number;
2577
- /**
2578
- * Cap on `deepLinkRoute` UTF-8 byte length. Default 1024 bytes — matches
2579
- * the route limit on `DeepLinkService.isValidRoute` so this field can be
2580
- * handed straight to the shell launcher without a second resize.
2581
- */
2582
- readonly maxDeepLinkRouteBytes: number;
2888
+ declare class FlyFileUploadComponent {
2889
+ private http;
2890
+ maxFiles: _angular_core.InputSignal<number>;
2891
+ maxFileSizeBytes: _angular_core.InputSignal<number>;
2892
+ accept: _angular_core.InputSignal<string>;
2893
+ sourceApp: _angular_core.InputSignal<string>;
2894
+ sourceEntityType: _angular_core.InputSignal<string | null>;
2895
+ sourceEntityId: _angular_core.InputSignal<string | null>;
2896
+ /** Optional: provide file IDs to auto-fetch metadata for pre-existing files (edit mode). */
2897
+ existingFileIds: _angular_core.InputSignal<string[] | null>;
2898
+ /** Two-way model for completed file metadata. */
2899
+ files: _angular_core.ModelSignal<FlyFileInfo[]>;
2900
+ filesChanged: _angular_core.OutputEmitterRef<FlyFileInfo[]>;
2901
+ error: _angular_core.WritableSignal<string | null>;
2902
+ dragging: _angular_core.WritableSignal<boolean>;
2903
+ slots: _angular_core.WritableSignal<UploadSlot[]>;
2904
+ /** Pre-existing files loaded from the entity (before any new uploads this session). */
2905
+ existingFiles: _angular_core.WritableSignal<FlyFileInfo[]>;
2906
+ fileInput: _angular_core.Signal<ElementRef<HTMLInputElement> | undefined>;
2907
+ constructor();
2908
+ allSlots: _angular_core.Signal<UploadSlot[]>;
2909
+ canAddMore: _angular_core.Signal<boolean>;
2910
+ limitHint: _angular_core.Signal<string>;
2911
+ triggerFileInput(): void;
2912
+ onDragOver(e: DragEvent): void;
2913
+ onDragLeave(e: DragEvent): void;
2914
+ onDrop(e: DragEvent): void;
2915
+ onFilesSelected(e: Event): void;
2916
+ removeSlot(slot: UploadSlot): void;
2917
+ removeExisting(f: FlyFileInfo): void;
2918
+ iconFor(slot: UploadSlot): string;
2919
+ iconForInfo(f: FlyFileInfo): string;
2920
+ formatFileSize(bytes: number): string;
2921
+ private processFiles;
2922
+ private uploadFile;
2923
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<FlyFileUploadComponent, never>;
2924
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<FlyFileUploadComponent, "fly-file-upload", never, { "maxFiles": { "alias": "maxFiles"; "required": false; "isSignal": true; }; "maxFileSizeBytes": { "alias": "maxFileSizeBytes"; "required": false; "isSignal": true; }; "accept": { "alias": "accept"; "required": false; "isSignal": true; }; "sourceApp": { "alias": "sourceApp"; "required": false; "isSignal": true; }; "sourceEntityType": { "alias": "sourceEntityType"; "required": false; "isSignal": true; }; "sourceEntityId": { "alias": "sourceEntityId"; "required": false; "isSignal": true; }; "existingFileIds": { "alias": "existingFileIds"; "required": false; "isSignal": true; }; "files": { "alias": "files"; "required": false; "isSignal": true; }; }, { "files": "filesChange"; "filesChanged": "filesChanged"; }, never, never, true, never>;
2583
2925
  }
2584
- declare const DEFAULT_AGENT_PAYLOAD_LIMITS: AgentPayloadLimits;
2585
- /**
2586
- * Stable failure reasons emitted by {@link validateAgentPayload}.
2587
- * - `invalid_version` — `version` !== {@link AGENT_PAYLOAD_VERSION}.
2588
- * - `invalid_kind` — `kind` is empty / not a string.
2589
- * - `field_too_large` — a string field inside `payload` exceeds `maxStringFieldBytes`.
2590
- * - `fallback_too_large` — `plainTextFallback` exceeds `maxPlainTextFallbackBytes`.
2591
- * - `json_too_large` — the full JSON.stringify(envelope) exceeds `maxJsonBytes`.
2592
- */
2593
- type AgentPayloadValidationResult = {
2594
- readonly ok: true;
2595
- } | {
2596
- readonly ok: false;
2597
- readonly reason: 'json_too_large' | 'fallback_too_large' | 'field_too_large' | 'invalid_version' | 'invalid_kind' | 'user_message_too_large' | 'system_context_too_many_entries' | 'system_context_value_too_large' | 'system_context_json_too_large' | 'too_many_attachments' | 'attachment_invalid_kind' | 'attachment_json_too_large' | 'attachment_text_too_large' | 'attachment_data_url_too_large' | 'mcp_scope_too_many_apis' | 'mcp_scope_api_too_large' | 'deep_link_route_too_large' | 'deep_link_route_invalid_shape';
2598
- /** Dotted property-access path to the offending field, e.g. `payload.title` or `payload.tags[2]`. NOT RFC 6901 JSON Pointer. */
2599
- readonly fieldPath?: string;
2600
- readonly actualBytes?: number;
2601
- readonly limitBytes?: number;
2602
- };
2603
2926
 
2604
2927
  /**
2605
2928
  * Singleton registry of slash commands offered by the agent input palette.
@@ -2722,6 +3045,24 @@ declare class AgentLookupRegistry {
2722
3045
  readonly appId: string;
2723
3046
  readonly route: string;
2724
3047
  } | null;
3048
+ /**
3049
+ * Resolve a deep-link target from a bare `(entity, id)` pair — the shape a
3050
+ * `/lookup` ref carries (it has no `<appId>.<entity>` kind token; the owning
3051
+ * app is implicit in the registered descriptor). `entity` is the registry's
3052
+ * unique storage key, so it identifies the descriptor unambiguously without
3053
+ * an app prefix.
3054
+ *
3055
+ * Returns `{ appId, route }` (the descriptor's {@link LookupDescriptor.appId}
3056
+ * / affinity `scope.appId` as the owner, `{id}` substituted URL-encoded) when
3057
+ * a matching descriptor carries a {@link LookupDescriptor.deepLinkRoute};
3058
+ * `null` otherwise (unknown entity, no template, or the owning app has since
3059
+ * unregistered) so callers render plain text rather than a dead link — the
3060
+ * same graceful-degrade contract as {@link resolveDeepLink}.
3061
+ */
3062
+ resolveDeepLinkForEntity(entity: string, id: string): {
3063
+ readonly appId: string;
3064
+ readonly route: string;
3065
+ } | null;
2725
3066
  /** Tear down by entity. Idempotent. */
2726
3067
  unregister(entity: string): void;
2727
3068
  /** Monotonic counter; identifies which registration call currently owns each entity. */
@@ -3268,6 +3609,6 @@ declare const AUDIENCE_ERROR_CODES: {
3268
3609
  };
3269
3610
  type AudienceErrorCode = (typeof AUDIENCE_ERROR_CODES)[keyof typeof AUDIENCE_ERROR_CODES];
3270
3611
 
3271
- export { AGENT_DRAG_MIME, AGENT_PAYLOAD_VERSION, APP_LOOKUP, AUDIENCE_ERROR_CODES, AUDIENCE_LIMITS, AUDIENCE_PRESETS, AUDIENCE_TERM_KINDS, AgentActionBus, AgentActionUnsupportedDispatchError, AgentCommandRegistry, AgentDropRegistry, AgentFlightAnimator, AgentLookupRegistry, AgentPayloadOversizeError, AudienceBuilderComponent, AuthService, ContextMenuComponent, DEFAULT_AGENT_PAYLOAD_LIMITS, DEFAULT_FLY_THEME_MODE, DialogResult, FLYOS_LAUNCH_EVENT, FLY_LOCALE_CATALOG, FLY_REMOTE_BASE_PATH, FLY_REMOTE_CONTEXT_EVENT, FLY_REMOTE_CONTEXT_STORE_KEY, FLY_REMOTE_ROUTES, FLY_THEME_MODE_IDS, FLY_WINDOW_HELP_HINT_EVENT, FlyAgentDraggableDirective, FlyBlockUiComponent, FlyFileUploadComponent, FlyImageUploadComponent, FlyRemoteContextService, FlyRemoteRouter, FlyRemoteRouterOutletComponent, FlySecureSrcDirective, FlyThemeService, FlyWindowHelpService, FlyosPendingLaunchesGlobalKey, I18nService, LAUNCH_CONTEXT, MessageBoxButtons, MessageBoxComponent, MessageBoxIcon, MessageBoxService, MockAuthService, RTL_LOCALE_SET, SHARE_ORG_CHART_SYSTEM_KEY_APPS, SHARE_ORG_CHART_SYSTEM_KEY_DEFAULT, SHARE_PANEL_DEFAULT_FILE_LEVELS, SUPPORTED_AGENT_PAYLOAD_VERSIONS, SharePanelComponent, SourceAppResolver, StandaloneWindowManagerService, TranslatePipe, WINDOW_DATA, WINDOW_HELP_HINT, WindowManagerService, findLocaleByDialect, findLocaleByPrefix, isRtlLocale, isRtlLocaleEntry, loadRemoteStyles, matchFlyRoutePattern, normalizeFlyTheme, trimAgentPayload, trimAgentString, unloadRemoteStyles, utf8ByteLength, validateAgentPayload };
3272
- export type { AgentAction, AgentActionDispatch, AgentActionVerb, AgentChipHostInputs, AgentCommand, AgentCommandContextBinding, AgentCommandHandle, AgentCommandRegistration, AgentCommandScope, AgentCommandSlashSpec, AgentDragPayload, AgentDraggableItem, AgentDropChipMode, AgentDropRendererRegistration, AgentEnvelopeAttachment, AgentMcpScope, AgentMessageEnvelope, AgentPayloadLimits, AgentPayloadValidationResult, AppEveryonePrincipal, AppEveryoneTerm, AppLookup, AppLookupEntry, AudienceEditTarget, AudienceErrorCode, AudienceFilter, AudienceOptions, AudiencePresetKind, AudienceTerm, AudienceTermKind, ChartTerm, ChildWindowData, ContextMenuItem, ContextMenuSection, DesktopApp, DesktopAppKind, DialogResultWithAcknowledgement, FlyFileInfo, FlyLaunchEventDetail, FlyLocaleEntry, FlyRemoteContext, FlyRemoteMatch, FlyRemoteRoute, FlyThemeMode, FlyWindowHelpHintEventDetail, FlyWindowHelpPublisher, FlyosPendingLaunches, LaunchContext, LoadBundleOptions, LookupDescriptor, LookupHandle, LookupRegistration, LookupResult, LookupSearch, MessageBoxButton, MessageBoxDontAskAgainConfig, MessageBoxOptions, MessageBoxOptionsWithAcknowledgement, MockAuthConfig, OpenWindowOptions, OuPrincipal, OuTerm, PresetTerm, RemoteAppDef, RoleOuLookupRow, RolePrincipal, RolesTerm, ShareOrgChartOption, ShareOuNode, SharePanelLevelOption, SharePermissionEntry, SharePrincipal, SharePrincipalKind, ShareUserResult, User, UserPrincipal, UsersTerm, WindowHelpHint, WindowInstance, WindowState };
3612
+ export { AGENT_DRAG_MIME, AGENT_PAYLOAD_VERSION, APP_LOOKUP, AUDIENCE_ERROR_CODES, AUDIENCE_LIMITS, AUDIENCE_PRESETS, AUDIENCE_TERM_KINDS, AgentActionBus, AgentActionUnsupportedDispatchError, AgentCommandRegistry, AgentDropRegistry, AgentFlightAnimator, AgentLookupRegistry, AgentPayloadOversizeError, AudienceBuilderComponent, AuthService, ContextMenuComponent, DEFAULT_AGENT_PAYLOAD_LIMITS, DEFAULT_FLY_THEME_MODE, DS_BASELINE_LOCALES, DialogResult, ENTITY_LINK_LAUNCHER, EntityLookupComponent, FLYOS_LAUNCH_EVENT, FLYOS_REMOTE_ROUTE_EVENT, FLY_LOCALE_CATALOG, FLY_REMOTE_BASE_PATH, FLY_REMOTE_CONTEXT_EVENT, FLY_REMOTE_CONTEXT_STORE_KEY, FLY_REMOTE_ROUTES, FLY_THEME_MODE_IDS, FLY_WINDOW_HELP_HINT_EVENT, FlyAgentDraggableDirective, FlyBlockUiComponent, FlyFileUploadComponent, FlyImageUploadComponent, FlyMarkdownEditorComponent, FlyRemoteContextService, FlyRemoteRouter, FlyRemoteRouterOutletComponent, FlySecureSrcDirective, FlyThemeService, FlyWindowHelpService, FlyosPendingLaunchesGlobalKey, FlyosShellOwnsHistoryGlobalKey, I18nService, LAUNCH_CONTEXT, MARKDOWN_TOOLBAR_PRESETS, MessageBoxButtons, MessageBoxComponent, MessageBoxIcon, MessageBoxService, MockAuthService, RTL_LOCALE_SET, SHARE_ORG_CHART_SYSTEM_KEY_APPS, SHARE_ORG_CHART_SYSTEM_KEY_DEFAULT, SHARE_PANEL_DEFAULT_FILE_LEVELS, SUPPORTED_AGENT_PAYLOAD_VERSIONS, SharePanelComponent, SourceAppResolver, StandaloneWindowManagerService, TranslatePipe, WINDOW_DATA, WINDOW_HELP_HINT, WindowManagerService, findLocaleByDialect, findLocaleByPrefix, isRtlLocale, isRtlLocaleEntry, loadRemoteStyles, matchFlyRoutePattern, normalizeFlyTheme, trimAgentPayload, trimAgentString, unloadRemoteStyles, utf8ByteLength, validateAgentPayload };
3613
+ export type { AgentAction, AgentActionDispatch, AgentActionVerb, AgentChipHostInputs, AgentCommand, AgentCommandContextBinding, AgentCommandHandle, AgentCommandRegistration, AgentCommandScope, AgentCommandSlashSpec, AgentDragPayload, AgentDraggableItem, AgentDropChipMode, AgentDropRendererRegistration, AgentEnvelopeAttachment, AgentMcpScope, AgentMessageEnvelope, AgentPayloadLimits, AgentPayloadValidationResult, AppEveryonePrincipal, AppEveryoneTerm, AppLookup, AppLookupEntry, AudienceEditTarget, AudienceErrorCode, AudienceFilter, AudienceOptions, AudiencePresetKind, AudienceTerm, AudienceTermKind, ChartTerm, ChildWindowData, ContextMenuItem, ContextMenuSection, DesktopApp, DesktopAppKind, DialogResultWithAcknowledgement, EntityLinkLauncher, EntityLinkSelection, FlyFileInfo, FlyLaunchEventDetail, FlyLocaleEntry, FlyRemoteContext, FlyRemoteMatch, FlyRemoteRoute, FlyRemoteRouteEventDetail, FlyThemeMode, FlyWindowHelpHintEventDetail, FlyWindowHelpPublisher, FlyosPendingLaunches, LaunchContext, LoadBundleOptions, LookupDescriptor, LookupHandle, LookupRegistration, LookupResult, LookupSearch, MarkdownToolbarItem, MarkdownToolbarPreset, MessageBoxButton, MessageBoxDontAskAgainConfig, MessageBoxOptions, MessageBoxOptionsWithAcknowledgement, MockAuthConfig, OpenWindowOptions, OuPrincipal, OuTerm, PresetTerm, RemoteAppDef, RoleOuLookupRow, RolePrincipal, RolesTerm, ShareOrgChartOption, ShareOuNode, SharePanelLevelOption, SharePermissionEntry, SharePrincipal, SharePrincipalKind, ShareUserResult, User, UserPrincipal, UsersTerm, WindowHelpHint, WindowInstance, WindowState };
3273
3614
  //# sourceMappingURL=mohamedatia-fly-design-system.d.ts.map