@mohamedatia/fly-design-system 2.12.0 → 2.14.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
 
@@ -860,8 +861,12 @@ interface LoadBundleOptions {
860
861
  /**
861
862
  * Shared I18nService for the shell and Business Apps.
862
863
  *
863
- * **Merge order** (later keys win): shell layer → remote bundles in registration order.
864
+ * **Merge order** (later keys win): DS baseline → shell layer → remote bundles
865
+ * in registration order.
864
866
  *
867
+ * - Baseline: {@link DS_BASELINE_LOCALES} — built-in strings for DS components
868
+ * (markdown editor, entity lookup) so they render localized labels even in a
869
+ * standalone consumer that never populated the shell layer. Always overridable.
865
870
  * - Shell: `setShellTranslations()` after loading `locale/{lang}.json` and API overrides.
866
871
  * - Remotes: `loadBundle()` per manifest `localeBaseUrl`.
867
872
  */
@@ -872,6 +877,9 @@ declare class I18nService {
872
877
  private readonly _bundleOrder;
873
878
  private readonly _locale;
874
879
  private readonly _version;
880
+ /** Built-in DS strings for the active locale (falls back to `en` for any
881
+ * locale we don't ship). Lowest-priority layer — always overridable. */
882
+ private readonly _baseline;
875
883
  private readonly _merged;
876
884
  readonly locale: _angular_core.Signal<string>;
877
885
  readonly version: _angular_core.Signal<number>;
@@ -893,6 +901,27 @@ declare class I18nService {
893
901
  static ɵprov: _angular_core.ɵɵInjectableDeclaration<I18nService>;
894
902
  }
895
903
 
904
+ /**
905
+ * Baseline UI strings for design-system components (markdown editor, entity
906
+ * lookup, …) in the four platform locales (`en`, `ar`, `fr`, `ur`).
907
+ *
908
+ * These are registered as the **lowest-priority** layer of {@link I18nService}
909
+ * (below the shell layer and any remote bundle), so DS components render real,
910
+ * localized labels even in a **standalone** consumer — a Business App running
911
+ * outside the desktop shell that never called `setShellTranslations()` — which
912
+ * would otherwise see raw keys (`common.label.bold`) as the pipe's fallback.
913
+ *
914
+ * Precedence: any consumer-supplied key with the same name still wins, so this
915
+ * is a safe default that an integrator can override without coordination.
916
+ *
917
+ * Scope: only the keys the **shippable** DS components reference today
918
+ * (`common.*` toolbar/link labels + `agent.lookup.*`). When a new DS component
919
+ * starts using `| translate`, add its keys here so it stays self-sufficient.
920
+ * Values are copied verbatim from the shell's `public/locale/*.json` — keep
921
+ * them in sync if either side changes.
922
+ */
923
+ declare const DS_BASELINE_LOCALES: Readonly<Record<string, Readonly<Record<string, string>>>>;
924
+
896
925
  /** Single source of truth for persisted / API theme strings. */
897
926
  declare const FLY_THEME_MODE_IDS: readonly ["light", "dark"];
898
927
  type FlyThemeMode = (typeof FLY_THEME_MODE_IDS)[number];
@@ -1213,16 +1242,135 @@ declare class FlyRemoteRouter {
1213
1242
  * In embedded mode: push a real browser history entry (so back/forward work)
1214
1243
  * and update the internal signal synchronously.
1215
1244
  *
1216
- * The state object carries `flyRemoteUrl` so the popstate listener can
1217
- * restore the exact URL without relying on window.location.pathname (which
1218
- * could be the shell's route, not the remote's logical URL).
1245
+ * The browser address bar is written as the shell's **canonical deep-link
1246
+ * form** `<shell-path>?app=<appId>&route=<remote-url>` NOT the bare remote
1247
+ * URL. This is what makes a hard reload work: on reload the shell's
1248
+ * `DeepLinkService` captures `?app=&route=` in its APP_INITIALIZER, re-opens
1249
+ * this app, and replays the route through the pending-launch pipeline
1250
+ * (`ShellLauncherService.launch` → `FLYOS_LAUNCH_EVENT` / pending registry →
1251
+ * the remote's root applies `ctx.route`). Writing the bare remote URL (e.g.
1252
+ * `/trends/abc`) instead would leave a host-unroutable path in the bar — on
1253
+ * reload the shell router falls through to its `**` wildcard, redirects to
1254
+ * `/desktop`, and the deep link is silently lost. See
1255
+ * skills/cross-app-deep-linking.md.
1256
+ *
1257
+ * `flyRemoteUrl` is still stashed in the history state so the popstate
1258
+ * listener restores the exact remote URL for back/forward without re-parsing
1259
+ * the query string.
1219
1260
  */
1220
1261
  private _pushEmbedded;
1262
+ /**
1263
+ * Build the browser-address-bar URL for an embedded navigation: the shell's
1264
+ * current path plus the canonical `?app=&route=` deep-link query (the same
1265
+ * contract `DeepLinkService.captureFromCurrentUrl` parses on cold load).
1266
+ *
1267
+ * The path is left untouched — only the query string carries the remote's
1268
+ * logical route — so the shell's own Angular Router (anchored at e.g.
1269
+ * `/desktop`) is never handed a path it cannot match.
1270
+ *
1271
+ * Fallback: when `appId` is unknown (WINDOW_DATA not injected — the Native
1272
+ * Federation token-split case where only `__FLYOS_SHELL__` proves embedding)
1273
+ * we cannot build a shareable link, so we return the shell path query-less.
1274
+ * Back/forward still work via the `flyRemoteUrl` history state; only
1275
+ * reload-restore is unavailable — no regression over leaving the bar as-is.
1276
+ */
1277
+ private _buildEmbeddedHistoryUrl;
1221
1278
  private buildUrl;
1222
1279
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<FlyRemoteRouter, never>;
1223
1280
  static ɵprov: _angular_core.ɵɵInjectableDeclaration<FlyRemoteRouter>;
1224
1281
  }
1225
1282
 
1283
+ /**
1284
+ * A federated remote's current navigation context, as published to the shell.
1285
+ *
1286
+ * `params` are the remote's **resolved route params** (e.g. `{ id: 'abc' }` for a
1287
+ * `trends/:id` match) — the remote owns its route table, so it resolves these and
1288
+ * the shell never has to know the remote's route patterns.
1289
+ */
1290
+ interface FlyRemoteContext {
1291
+ /** Owning app id — matches the shell's app registry and `AgentCommandScope.appId`. */
1292
+ readonly appId: string;
1293
+ /** Logical remote URL, e.g. `/trends/abc`. Query/hash stripped by the publisher. */
1294
+ readonly url: string;
1295
+ /** `url` split into path segments, e.g. `['trends', 'abc']`. */
1296
+ readonly segments: readonly string[];
1297
+ /** Resolved route params, e.g. `{ id: 'abc' }`. Empty when no param route matched. */
1298
+ readonly params: Readonly<Record<string, string>>;
1299
+ }
1300
+ /**
1301
+ * Shared cross-bundle store key + sync event. **Public contract** — a remote that
1302
+ * cannot consume a DS new enough to back {@link FlyRemoteContextService.publish} on
1303
+ * `globalThis` itself may write this slot directly (same shape, keyed by appId) and
1304
+ * dispatch {@link FLY_REMOTE_CONTEXT_EVENT} to notify the shell. Keep these literals
1305
+ * stable; they are an integration boundary, not an implementation detail.
1306
+ */
1307
+ declare const FLY_REMOTE_CONTEXT_STORE_KEY = "__flyRemoteContext__";
1308
+ declare const FLY_REMOTE_CONTEXT_EVENT = "fly:remote-context";
1309
+ /**
1310
+ * Remote → shell route/context channel.
1311
+ *
1312
+ * Why this exists
1313
+ * ---------------
1314
+ * A federated remote (e.g. Circles) renders inside a desktop-shell window and
1315
+ * keeps its own internal Angular route (`/trends/:id`). The shell cannot see that
1316
+ * route: the remote provides {@link FlyRemoteRouter} at its **component** injector
1317
+ * (so it can read per-window `WINDOW_DATA`), which makes the route state invisible
1318
+ * to the host. Shell-side features that need "what is the user looking at right
1319
+ * now" — most importantly Category-B slash commands whose `contextBindings` include
1320
+ * a `lookup`/`route` entity id — had no way to resolve the current entity id, and
1321
+ * degraded to "ask the user".
1322
+ *
1323
+ * The channel — why `globalThis`, not the DI singleton
1324
+ * ----------------------------------------------------
1325
+ * This service is `providedIn: 'root'`, but a root instance is **NOT** reliably
1326
+ * shared across the federation boundary. The shell builds the design system from
1327
+ * workspace SOURCE while remotes consume the PUBLISHED npm package; Native
1328
+ * Federation only collapses those two physical builds into one runtime instance if
1329
+ * version negotiation succeeds perfectly (matching advertised `mappingVersion`,
1330
+ * `singleton`, compatible ranges). That negotiation has silently split before —
1331
+ * giving the shell and a remote *separate* `providedIn:'root'` instances, so a
1332
+ * value published on one was invisible to the other.
1333
+ *
1334
+ * `globalThis` is the one substrate guaranteed shared across every federated bundle
1335
+ * in the same realm (there are no iframes), so the channel stores its state there
1336
+ * (see {@link FLY_REMOTE_CONTEXT_STORE_KEY}). {@link context} / {@link param} read
1337
+ * it directly — split-proof, synchronous, no injector-token gymnastics. A per-
1338
+ * instance signal mirrors the store for reactive consumers and is re-synced from a
1339
+ * `globalThis` event whenever any copy of the service (or a remote writing the slot
1340
+ * directly) mutates it. The same pattern already backs the shell's app-launch
1341
+ * context bridge, so this is an established boundary, not a new hack.
1342
+ *
1343
+ * Contract
1344
+ * --------
1345
+ * - Remote: call {@link publish} whenever its embedded route changes, and
1346
+ * {@link clear} on teardown (window close / component destroy).
1347
+ * - Shell: call {@link context} (or {@link param}) for an app id to resolve bindings.
1348
+ *
1349
+ * Keyed by `appId` (last publisher wins) — a single live window per app is the v1
1350
+ * assumption; a windowId key is the natural extension if multi-window-per-app
1351
+ * dispatch is ever needed.
1352
+ */
1353
+ declare class FlyRemoteContextService {
1354
+ private readonly _byApp;
1355
+ /** All currently-published contexts, keyed by app id. Reactive. */
1356
+ readonly contexts: _angular_core.Signal<ReadonlyMap<string, FlyRemoteContext>>;
1357
+ constructor();
1358
+ /** Publish (or replace) the active route context for an app. */
1359
+ publish(ctx: FlyRemoteContext): void;
1360
+ /** Drop an app's context (remote unmounted / window closed). No-op if absent. */
1361
+ clear(appId: string): void;
1362
+ /** Current context for an app, or `null` when nothing is published. */
1363
+ context(appId: string): FlyRemoteContext | null;
1364
+ /**
1365
+ * Resolve a single route param for an app, e.g. `param('circles', 'id')`.
1366
+ * Returns `null` when the app has no published context or the param is absent —
1367
+ * the caller then degrades (the skill asks for the missing id).
1368
+ */
1369
+ param(appId: string, path: string): string | null;
1370
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<FlyRemoteContextService, never>;
1371
+ static ɵprov: _angular_core.ɵɵInjectableDeclaration<FlyRemoteContextService>;
1372
+ }
1373
+
1226
1374
  /**
1227
1375
  * Minimal adapter the shell (or any host) provides so design-system services can
1228
1376
  * look up apps without depending on `AppRegistryService` directly. Keeps the
@@ -1588,760 +1736,1154 @@ declare class MockAuthService {
1588
1736
  static ɵprov: _angular_core.ɵɵInjectableDeclaration<MockAuthService>;
1589
1737
  }
1590
1738
 
1591
- interface ContextMenuItem {
1592
- id: string;
1593
- label: string;
1594
- icon: string;
1595
- }
1596
- interface ContextMenuSection {
1597
- label?: string;
1598
- items: ContextMenuItem[];
1599
- }
1600
- declare class ContextMenuComponent implements AfterViewInit, OnDestroy {
1601
- private menuEl?;
1602
- private readonly doc;
1603
- private readonly hostEl;
1604
- x: _angular_core.InputSignal<number>;
1605
- y: _angular_core.InputSignal<number>;
1606
- sections: _angular_core.InputSignal<ContextMenuSection[]>;
1607
- action: _angular_core.OutputEmitterRef<string>;
1608
- closed: _angular_core.OutputEmitterRef<void>;
1609
- private menuWidth;
1610
- private menuHeight;
1611
- private previouslyFocused;
1612
- clampedPos: _angular_core.Signal<{
1613
- left: number;
1614
- top: number;
1615
- }>;
1616
- ngAfterViewInit(): void;
1617
- ngOnDestroy(): void;
1618
- onAction(id: string): void;
1619
- onClickOutside(event: MouseEvent): void;
1620
- onEscape(): void;
1621
- onContextMenu(event: MouseEvent): void;
1622
- onKeydown(event: KeyboardEvent): void;
1623
- private close;
1624
- private getMenuItems;
1625
- private focusItem;
1626
- private restoreFocus;
1627
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<ContextMenuComponent, never>;
1628
- 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>;
1629
- }
1630
-
1631
- declare enum MessageBoxButtons {
1632
- OK = 0,
1633
- OKCancel = 1,
1634
- YesNo = 2,
1635
- YesNoCancel = 3,
1636
- RetryCancel = 4,
1637
- AbortRetryIgnore = 5
1638
- }
1639
- declare enum MessageBoxIcon {
1640
- None = 0,
1641
- Information = 1,
1642
- Warning = 2,
1643
- Error = 3,
1644
- Question = 4
1645
- }
1646
- declare enum DialogResult {
1647
- None = 0,
1648
- OK = 1,
1649
- Cancel = 2,
1650
- Yes = 3,
1651
- No = 4,
1652
- Retry = 5,
1653
- Abort = 6,
1654
- Ignore = 7
1655
- }
1656
- interface MessageBoxOptions {
1657
- title: string;
1658
- message: string;
1659
- buttons?: MessageBoxButtons;
1660
- icon?: MessageBoxIcon;
1661
- }
1662
1739
  /**
1663
- * Configuration for the "Don't ask again" checkbox rendered by
1664
- * `showAcknowledged()`. The field is intentionally NOT part of the base
1665
- * `MessageBoxOptions` so the type system enforces the rule
1666
- * "checkbox caller MUST use `showAcknowledged()`": the classic `show()`
1667
- * entry point cannot accept this shape, eliminating the silent-discard
1668
- * dark-pattern path where the user's choice was thrown away.
1740
+ * Agent input contracts.
1741
+ *
1742
+ * These types define the wire and DI surface for the new `<fly-agent-input>` orchestrator
1743
+ * (Phase 2+). Phase 1 ships only the contracts: payload envelope, command/drop registry
1744
+ * shapes, and chip-host inputs. The concrete components consume them later.
1745
+ *
1746
+ * Design rules:
1747
+ * - All fields are `readonly` — the registries store these in signal stores and we never
1748
+ * want a host mutating after registration. Hosts construct fresh objects to update.
1749
+ * - The discriminated kinds (`scope`, `mode`, `kind`) carry the entire variance — no
1750
+ * boolean flags. New variants extend the union without breaking existing consumers.
1751
+ * - The `Type<AgentChipHostInputs<T>>` shape is intentional: chip components declare
1752
+ * `payload`, `mode`, optional `onRemove` as Angular `input()` signals; the registry
1753
+ * wires them via `NgComponentOutlet` inputs in the consumer. The component reference
1754
+ * itself never leaks across the federation boundary by value — only by class identity.
1669
1755
  */
1670
- interface MessageBoxDontAskAgainConfig {
1671
- /** i18n key for the checkbox label, e.g. 'agent.command.builtin.clear.dont_ask_again'. */
1672
- labelKey: string;
1673
- /** Initial checked state. Default false. */
1674
- defaultChecked?: boolean;
1756
+ /** Frozen MIME used by `flyAgentDraggable` and the drop-zone reader. Never change without a DS major. */
1757
+ declare const AGENT_DRAG_MIME: "application/x-fly-agent-payload+json";
1758
+ /**
1759
+ * Frozen payload envelope version.
1760
+ *
1761
+ * v1 — minimal drag payload: kind / appId / version / payload / plainTextFallback /
1762
+ * suggestedCommandIds. Still used by the drag/drop surface.
1763
+ *
1764
+ * v2 — bus envelope ({@link AgentMessageEnvelope}). Adds optional `userMessage`,
1765
+ * `systemContext`, `attachments`, `mcpScope` so a dispatcher can give the agent
1766
+ * rich context without polluting the user-visible message bubble. v2 is a
1767
+ * superset of v1 — every v1 payload is a valid v2 payload — so the version
1768
+ * number ratchets forward without breaking existing callers.
1769
+ */
1770
+ declare const AGENT_PAYLOAD_VERSION: 2;
1771
+ /**
1772
+ * Versions accepted by the validator. v1 payloads (the drag/drop surface) remain valid;
1773
+ * v2 adds the optional bus-envelope fields. Renderers narrow on `version` when they need
1774
+ * to.
1775
+ */
1776
+ declare const SUPPORTED_AGENT_PAYLOAD_VERSIONS: readonly number[];
1777
+ /**
1778
+ * Where a command surfaces. `'global'` = always offered. `{ appId }` = offered only when
1779
+ * the host's live `liveAppIds` set (passed to {@link AgentCommandRegistry.visible}) contains
1780
+ * that id. This lets a remote register its slash command at boot but only have it appear
1781
+ * in the palette while at least one of the remote's windows is open.
1782
+ */
1783
+ type AgentCommandScope = 'global' | {
1784
+ readonly appId: string;
1785
+ };
1786
+ /**
1787
+ * A slash command offered by the agent input palette. Commands are deliberately shallow
1788
+ * descriptors — the host (shell) decides what happens on Send. The descriptor's role is
1789
+ * to make the palette row renderable (icon, label, kbd hint, app badge) and matchable
1790
+ * (id, aliases, drop-kind suggestions) without coupling DS to any business logic.
1791
+ */
1792
+ interface AgentCommand {
1793
+ /** Stable id, kebab-case. Becomes the slash text after `/`, e.g. `/analyze-trend`. */
1794
+ readonly id: string;
1795
+ /** i18n key for the visible label, e.g. `agent.command.analyze_trend.label`. */
1796
+ readonly labelKey: string;
1797
+ /** i18n key for an optional sublabel / description shown beneath the label. */
1798
+ readonly descriptionKey?: string;
1799
+ /** PrimeIcons class, e.g. `pi-chart-line`. */
1800
+ readonly icon?: string;
1801
+ /** App badge label key — appears as a small tag, e.g. `agent.command.app_badge.circles`. */
1802
+ readonly appBadgeKey?: string;
1803
+ /** Optional kbd hint i18n key. */
1804
+ readonly kbdHintKey?: string;
1805
+ /** When the command is keyword-matched against drop payload kinds, list those kinds here. */
1806
+ readonly suggestForDropKinds?: readonly string[];
1807
+ /** Extra match terms beyond id + label, used by the fuzzy filter. */
1808
+ readonly aliases?: readonly string[];
1809
+ /** When `'send'`, the command is inserted as a bound prefix and executed on Send. */
1810
+ readonly executeOn: 'send';
1811
+ /** Optional client-side gate. Return false to hide the command in this scope. */
1812
+ readonly isVisible?: () => boolean;
1813
+ /**
1814
+ * Category B (PR3): when present, selecting this command invokes a
1815
+ * manifest-declared app skill instead of sending the composed text as a plain
1816
+ * message. The host dispatches a Twin message carrying
1817
+ * `system_context.slash_command_key = slashCommand.key` plus resolved context.
1818
+ * See {@link AgentCommandSlashSpec}.
1819
+ */
1820
+ readonly slashCommand?: AgentCommandSlashSpec;
1675
1821
  }
1676
1822
  /**
1677
- * Options narrowed to those carrying a `dontAskAgain` config the only shape
1678
- * accepted by `showAcknowledged()`.
1823
+ * A context binding that resolves one `system_context` value for a Category B
1824
+ * command at dispatch. Pure data so it travels app-agnostically in the
1825
+ * Controller's app federation metadata (no callbacks). Discriminated by `from`:
1826
+ *
1827
+ * - `route` — value from the owning app's current route param `path`. The
1828
+ * shell cannot read a federated remote's internal route, so route
1829
+ * bindings **degrade** in v1 (the skill asks for the missing id);
1830
+ * resolved only once a remote→shell route channel exists.
1831
+ * - `lookup` — the host opens the `/lookup` entity picker for `entity` and
1832
+ * writes the picked id into `system_context[key]` (picker-during-
1833
+ * dispatch is a v1 follow-up — degrades to "ask" until then).
1834
+ * - `constant` — a literal value written into `system_context[key]`.
1679
1835
  */
1680
- interface MessageBoxOptionsWithAcknowledgement extends MessageBoxOptions {
1681
- dontAskAgain: MessageBoxDontAskAgainConfig;
1836
+ type AgentCommandContextBinding = {
1837
+ readonly key: string;
1838
+ readonly from: 'route';
1839
+ readonly path: string;
1840
+ } | {
1841
+ readonly key: string;
1842
+ readonly from: 'lookup';
1843
+ readonly entity: string;
1844
+ readonly exclude?: readonly string[];
1845
+ readonly promptKey?: string;
1846
+ } | {
1847
+ readonly key: string;
1848
+ readonly from: 'constant';
1849
+ readonly value: string;
1850
+ };
1851
+ /**
1852
+ * Category B slash-command dispatch metadata (PR3). Travels app-agnostically in
1853
+ * the Controller's app federation metadata and is registered by the shell's
1854
+ * `RemoteManifestService` (the same path that registers `/lookup` descriptors) —
1855
+ * remotes do NOT self-register. When an {@link AgentCommand} carries this,
1856
+ * selecting it dispatches a Twin message with `system_context.slash_command_key
1857
+ * = key`, merged with the resolved `contextBindings`.
1858
+ */
1859
+ interface AgentCommandSlashSpec {
1860
+ /** Dispatched as `system_context.slash_command_key`; matches the agents-side
1861
+ * skill's `slash_command_key` (= its manifest_key). */
1862
+ readonly key: string;
1863
+ /** Reserved: a future confirm step before dispatch (manifest `requiresConfirmation`). */
1864
+ readonly requiresConfirmation?: boolean;
1865
+ /** Parameter sources resolved into `system_context` at dispatch. */
1866
+ readonly contextBindings?: readonly AgentCommandContextBinding[];
1682
1867
  }
1683
- interface MessageBoxButton {
1684
- label: string;
1685
- result: DialogResult;
1686
- variant?: 'primary' | 'danger' | 'default';
1868
+ /** What hosts pass to {@link AgentCommandRegistry.register}. Adds the scope to {@link AgentCommand}. */
1869
+ interface AgentCommandRegistration extends AgentCommand {
1870
+ readonly scope: AgentCommandScope;
1687
1871
  }
1688
- /** Shape returned by `showAcknowledged()` — pairs the dialog result with the checkbox state. */
1689
- interface DialogResultWithAcknowledgement {
1690
- readonly result: DialogResult;
1691
- readonly dontAskAgain: boolean;
1872
+ /** Disposable handle returned by {@link AgentCommandRegistry.register}. Idempotent `dispose()`. */
1873
+ interface AgentCommandHandle {
1874
+ dispose(): void;
1692
1875
  }
1693
- declare class MessageBoxService {
1694
- private readonly i18n;
1695
- readonly visible: _angular_core.WritableSignal<boolean>;
1696
- readonly title: _angular_core.WritableSignal<string>;
1697
- readonly message: _angular_core.WritableSignal<string>;
1698
- readonly icon: _angular_core.WritableSignal<MessageBoxIcon>;
1699
- readonly buttons: _angular_core.WritableSignal<MessageBoxButton[]>;
1876
+ /**
1877
+ * How a lookup fetches candidate entities. The picker calls the app's existing
1878
+ * authenticated REST search endpoint (the same one the agent's MCP `*_list_brief`
1879
+ * tool wraps) through the shell's HttpClient — gateway routing + auth
1880
+ * interceptor apply. We deliberately do NOT route typeahead through MCP (agent-
1881
+ * shaped, agent-auth) or the dataset executor (aggregation-shaped, no fulltext).
1882
+ *
1883
+ * Field mapping is declarative because entities differ: Circles trends/signals
1884
+ * expose `/brief` endpoints returning `{ id, title, status }`, while scenarios
1885
+ * have no brief variant and return full objects with `titleEn` / `titleAr`. The
1886
+ * `displayField` / `secondaryField` indirection absorbs that per-entity skew so
1887
+ * one picker component serves them all.
1888
+ */
1889
+ interface LookupSearch {
1700
1890
  /**
1701
- * Active "Don't ask again" config populated only by `showAcknowledged()`.
1702
- * `show()` callers cannot reach this signal because the type system rejects
1703
- * `dontAskAgain` on the base `MessageBoxOptions`.
1891
+ * Relative REST path the picker GETs, e.g. `/api/circles/trends/brief`. Must
1892
+ * be a relative path (no scheme/host) the SSRF guard at onboard time (when
1893
+ * the descriptor is manifest-backed) and the picker both reject absolute URLs.
1704
1894
  */
1705
- readonly dontAskAgain: _angular_core.WritableSignal<MessageBoxDontAskAgainConfig | undefined>;
1895
+ readonly endpoint: string;
1896
+ /** Query param carrying the typed text, e.g. `search`. */
1897
+ readonly queryParam: string;
1898
+ /** Static query params merged into every request, e.g. `{ pageSize: '10' }`. */
1899
+ readonly extraParams?: Readonly<Record<string, string>>;
1900
+ /** Response-item field holding the entity id. Default `id`. */
1901
+ readonly idField?: string;
1902
+ /** Response-item field holding the display label, e.g. `title` / `titleEn`. */
1903
+ readonly displayField: string;
1904
+ /** Optional response-item field for the chip's secondary line (status, category). */
1905
+ readonly secondaryField?: string;
1706
1906
  /**
1707
- * Component-side checkbox state. The component (`MessageBoxComponent`) wires
1708
- * its own signal to this one; the service explicitly re-seeds it on every
1709
- * `_open()` so reusing a constant `options` literal across two opens does
1710
- * NOT leak the previous user's checkbox state through signal `===` dedupe.
1711
- * Exposed for the component to read/write; not for general callers.
1907
+ * Optional response-item field whose value is a *row-level* app id — i.e. the
1908
+ * app that owns this individual entity, distinct from the descriptor's
1909
+ * {@link LookupDescriptor.appId} (which only names the app exposing the
1910
+ * lookup endpoint). Help articles are the motivating case: every article is
1911
+ * exposed by `help-center`, but each one was seeded by a *source* app's
1912
+ * manifest (Circles, Trends, …). Surfacing that per-row appId lets the
1913
+ * picker render a second source-app tag so the user can tell two
1914
+ * similarly-titled rows from different source apps apart at a glance.
1915
+ *
1916
+ * Resolved through {@link LookupResult.appId} and the shell's app registry
1917
+ * with the same fallback chain used for {@link LookupDescriptor.appId}.
1712
1918
  */
1713
- readonly dontAskAgainChecked: _angular_core.WritableSignal<boolean>;
1714
- private resolver;
1715
- show(options: MessageBoxOptions): Promise<DialogResult>;
1919
+ readonly appIdField?: string;
1716
1920
  /**
1717
- * Opens a message box with a "Don't ask again" checkbox and resolves to both
1718
- * the dialog result and the checkbox state. Throws when `options.dontAskAgain`
1719
- * is missing the checkbox config is mandatory for this entry point. The
1720
- * compile-time signature already guarantees presence; the runtime check is
1721
- * defense-in-depth for callers that bypass the type system via `as never`.
1921
+ * Dotted path to the results array within the response body when it is
1922
+ * wrapped, e.g. `items` for `{ items: [...], total }`. Omit when the response
1923
+ * body IS the array.
1722
1924
  */
1723
- showAcknowledged(options: MessageBoxOptionsWithAcknowledgement): Promise<DialogResultWithAcknowledgement>;
1724
- resolve(result: DialogResult, dontAskAgain?: boolean): void;
1725
- private _open;
1726
- private resolveButtons;
1727
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<MessageBoxService, never>;
1728
- static ɵprov: _angular_core.ɵɵInjectableDeclaration<MessageBoxService>;
1925
+ readonly resultsPath?: string;
1729
1926
  }
1730
-
1731
- declare class MessageBoxComponent implements AfterViewInit {
1732
- service: MessageBoxService;
1733
- private elRef;
1734
- readonly MessageBoxIcon: typeof MessageBoxIcon;
1735
- readonly DialogResult: typeof DialogResult;
1736
- /** Mirror of the service's `dontAskAgain` config so the template can read it directly. */
1737
- readonly dontAskAgainConfig: _angular_core.Signal<_mohamedatia_fly_design_system.MessageBoxDontAskAgainConfig | undefined>;
1927
+ /**
1928
+ * A lookupable entity offered by the `/lookup` palette. Registered by the owning
1929
+ * app (a federation remote self-registers at boot, mirroring {@link AgentCommand})
1930
+ * or, once manifest-backed, projected from the app's `lookups[]` manifest section.
1931
+ *
1932
+ * The descriptor is a shallow, business-logic-free descriptor: it tells the
1933
+ * picker WHAT to search, WHERE it is offered, and HOW to map the response — the
1934
+ * picker owns the typeahead UX, the shell owns the HTTP call.
1935
+ */
1936
+ interface LookupDescriptor {
1738
1937
  /**
1739
- * User-driven checkbox state, owned by the service and re-seeded on every
1740
- * `_open()` so reusing a constant options literal cannot leak prior state.
1938
+ * Stable entity key, kebab/lower, e.g. `scenario`. Doubles as the `/lookup
1939
+ * <entity>` sub-token and the group key the picked ref is grouped under when
1940
+ * serialized for the agent.
1741
1941
  */
1742
- readonly dontAskAgainChecked: _angular_core.WritableSignal<boolean>;
1942
+ readonly entity: string;
1943
+ /** i18n key for the entity's display name in the picker / palette. */
1944
+ readonly labelKey: string;
1945
+ /** Optional PrimeIcons class for the picker row + chip. */
1946
+ readonly icon?: string;
1743
1947
  /**
1744
- * Concatenated id list for the dialog's `aria-describedby`. Always includes
1745
- * the message; appends the checkbox label id when the checkbox is rendered
1746
- * so screen readers announce the checkbox as part of the description.
1948
+ * Stable id of the app that exposes this lookup, e.g. `notes`, `calendar`,
1949
+ * `circles`. The picker resolves it to the app's display name via the shell's
1950
+ * app registry and renders an "exposed by …" badge so the user can see which
1951
+ * app owns the entity they're browsing (helps disambiguate when two apps
1952
+ * register a similar-sounding entity, e.g. both Tasks and Notes one day).
1953
+ *
1954
+ * Populated automatically by the shell's registration paths:
1955
+ * - `CORE_APP_LOOKUPS` stamps it per descriptor at hand-edit time.
1956
+ * - `RemoteManifestService` stamps it from the manifest entry's `id` so
1957
+ * federation remotes don't have to repeat the id in every descriptor.
1958
+ *
1959
+ * Falls back to {@link appBadgeKey} (a locale-resolved literal) when an
1960
+ * entity has no first-class home in the shell's app registry — e.g. `user`,
1961
+ * `app-agent`, `robot`. When neither is set the picker omits the badge.
1747
1962
  */
1748
- readonly ariaDescribedBy: _angular_core.Signal<"mb-message mb-dont-ask" | "mb-message">;
1749
- private previouslyFocused;
1750
- ngAfterViewInit(): void;
1751
- onEscape(): void;
1752
- onBackdropClick(): void;
1753
- onButtonClick(result: DialogResult): void;
1754
- onDontAskAgainToggle(ev: Event): void;
1755
- iconClass(): string;
1756
- private focusPrimaryButton;
1757
- private restoreFocus;
1758
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<MessageBoxComponent, never>;
1759
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<MessageBoxComponent, "fly-message-box", never, {}, {}, never, never, true, never>;
1760
- }
1761
-
1762
- /** Full-bleed loading overlay for window content (shell) or embedded hosts. */
1763
- declare class FlyBlockUiComponent {
1764
- /** When false, the overlay is not rendered (host may use @if instead). */
1765
- active: _angular_core.InputSignal<boolean>;
1766
- /** i18n key for status text; empty uses `common.loading`. */
1767
- messageKey: _angular_core.InputSignal<string>;
1768
- readonly resolvedMessageKey: _angular_core.Signal<string>;
1769
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<FlyBlockUiComponent, never>;
1770
- 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>;
1963
+ readonly appId?: string;
1964
+ /**
1965
+ * Optional i18n key the picker uses for the "exposed by …" badge **when
1966
+ * {@link appId} is absent or unknown to the shell's app registry**. Lets
1967
+ * entities that don't map to a single app (Users, Robots, App Agents) still
1968
+ * surface a meaningful badge instead of silently omitting it. The picker
1969
+ * resolves the key via the shared i18n service so the badge follows the
1970
+ * user's locale.
1971
+ */
1972
+ readonly appBadgeKey?: string;
1973
+ /**
1974
+ * Advisory MCP tool-key prefixes the agent should prefer when the user
1975
+ * references this entity via `/lookup` (e.g. `['dashboard.reports']`). The
1976
+ * shell folds these into the turn's `mcp_scope` so the Twin self-serves the
1977
+ * owning app's tools fetching and analysing the referenced entity itself —
1978
+ * instead of defaulting to a specialist-Robot consult for "tell me more"
1979
+ * style prompts. Same dot-namespaced prefix vocabulary as
1980
+ * {@link AgentMcpScope.apis}. Omit for entities with no first-class MCP tool
1981
+ * family (e.g. `user`, `robot`).
1982
+ */
1983
+ readonly mcpApis?: readonly string[];
1984
+ /**
1985
+ * Optional in-app deep-link route TEMPLATE for this entity's detail page,
1986
+ * e.g. `'/signals/{id}'`. When present, the desktop shell turns an agent's
1987
+ * inline reference to this entity — the `flyos:<appId>.<entity>/<id>`
1988
+ * anchors the agents backend emits in chat answers — into a launchable
1989
+ * link: the single `{id}` placeholder is substituted with the referenced
1990
+ * entity's id (URL-encoded) and the owning {@link appId} is launched on
1991
+ * that route via the shell launcher.
1992
+ *
1993
+ * Omit for entities with no standalone detail page — their references then
1994
+ * render as plain text (graceful degrade; never a dead link). The owning
1995
+ * app declares this once in its `lookups[]` manifest entry, so a remote
1996
+ * becomes agent-deep-linkable without any shell or design-system change.
1997
+ * Only `{id}` is substituted here — richer parameterisation rides the
1998
+ * deep-link `params` channel, not this template.
1999
+ */
2000
+ readonly deepLinkRoute?: string;
2001
+ /** How to fetch + map candidates. */
2002
+ readonly search: LookupSearch;
1771
2003
  }
1772
-
1773
- /**
1774
- * Metadata returned by Files Manager after a successful upload or metadata query.
1775
- * Mirrors the `FileMetadataDto` shape from `GET /api/files/{id}` and `POST /api/files/upload`.
1776
- */
1777
- interface FlyFileInfo {
1778
- id: string;
1779
- fileName: string;
1780
- contentType: string;
1781
- sizeBytes: number;
1782
- sourceApp: string;
1783
- sourceEntityType?: string;
1784
- sourceEntityId?: string;
1785
- uploadedByUserId?: string;
1786
- correlationId?: string;
1787
- isConfirmed: boolean;
1788
- version: number;
1789
- scanStatus: string;
1790
- createdAt: string;
1791
- folderId?: string;
1792
- hasErrors: boolean;
2004
+ /** What hosts pass to the lookup registry. Adds the scope to {@link LookupDescriptor}. */
2005
+ interface LookupRegistration extends LookupDescriptor {
2006
+ /**
2007
+ * Affinity hint, NOT a visibility gate.
2008
+ *
2009
+ * Unlike {@link AgentCommandScope} — where `{appId}` HIDES a command unless the
2010
+ * app is live — lookup scope is a *priority hint*. Every registered lookup is
2011
+ * always offered in `/lookup`; when the app named by `{appId}` is in the host's
2012
+ * live app set, that lookup sorts to the **top** of the entity picker so the
2013
+ * "what am I working on right now?" entities surface first. `'global'` lookups
2014
+ * have no affinity and sort after app-affinity matches.
2015
+ *
2016
+ * Rationale: OS-core entities (note, calendar event, file) are always
2017
+ * referenceable — there's no "open the app first" condition the way there is
2018
+ * for federated remotes — so a visibility gate would just produce a confusing
2019
+ * empty state. Affinity-as-sort preserves the "Circles is open → prefer
2020
+ * scenarios/trends/signals" intuition without hiding the rest.
2021
+ */
2022
+ readonly scope: AgentCommandScope;
1793
2023
  }
1794
-
1795
- /**
1796
- * Image upload component with built-in cropperjs cropping modal.
1797
- *
1798
- * Usage:
1799
- * ```html
1800
- * <fly-image-upload
1801
- * [aspectRatio]="16/9"
1802
- * [currentImageId]="trend.coverImageId"
1803
- * sourceApp="circles"
1804
- * sourceEntityType="trend"
1805
- * (uploaded)="onImageUploaded($event)"
1806
- * (removed)="onImageRemoved()"
1807
- * />
1808
- * ```
1809
- */
1810
- declare class FlyImageUploadComponent {
1811
- private http;
1812
- private injector;
1813
- aspectRatio: _angular_core.InputSignal<number>;
1814
- maxSizeBytes: _angular_core.InputSignal<number>;
1815
- currentImageId: _angular_core.InputSignal<string | null>;
1816
- sourceApp: _angular_core.InputSignal<string>;
1817
- sourceEntityType: _angular_core.InputSignal<string | null>;
1818
- sourceEntityId: _angular_core.InputSignal<string | null>;
1819
- uploaded: _angular_core.OutputEmitterRef<FlyFileInfo>;
1820
- removed: _angular_core.OutputEmitterRef<void>;
1821
- uploading: _angular_core.WritableSignal<boolean>;
1822
- error: _angular_core.WritableSignal<string | null>;
1823
- showCropper: _angular_core.WritableSignal<boolean>;
1824
- rawImageUrl: _angular_core.WritableSignal<string>;
1825
- localBlob: _angular_core.WritableSignal<string | null>;
1826
- fileInput: _angular_core.Signal<ElementRef<HTMLInputElement> | undefined>;
1827
- cropImage: _angular_core.Signal<ElementRef<HTMLImageElement> | undefined>;
1828
- private cropper;
1829
- private selectedFile;
1830
- /** Resolved preview URL — uses blob for local uploads, fetches authenticated for existing images */
1831
- previewUrl: _angular_core.WritableSignal<string | null>;
1832
- constructor();
1833
- sizeHint: _angular_core.Signal<string>;
1834
- triggerFileInput(): void;
1835
- onDragOver(e: DragEvent): void;
1836
- onDrop(e: DragEvent): void;
1837
- onFileSelected(e: Event): void;
1838
- removeImage(): void;
1839
- cancelCrop(): void;
1840
- applyCrop(): void;
1841
- private processFile;
1842
- private initCropper;
1843
- private destroyCropper;
1844
- private uploadFile;
1845
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<FlyImageUploadComponent, never>;
1846
- 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>;
2024
+ /** One resolved row the picker returns once the user selects a candidate. */
2025
+ interface LookupResult {
2026
+ /** The entity kind (echoes {@link LookupDescriptor.entity}). */
2027
+ readonly entity: string;
2028
+ /** Selected entity id. */
2029
+ readonly id: string;
2030
+ /** Selected entity's display label. */
2031
+ readonly label: string;
2032
+ /** Optional secondary detail (status / category). */
2033
+ readonly secondary?: string;
2034
+ /**
2035
+ * Row-level source app id (e.g. `circles` for an article seeded by Circles'
2036
+ * manifest). Populated when the descriptor sets {@link LookupSearch.appIdField}
2037
+ * and the response item carries a non-empty value. The picker renders it as
2038
+ * a second app tag alongside the descriptor-level badge so the user can see
2039
+ * "this Help-Center article was contributed by Circles" without opening it.
2040
+ */
2041
+ readonly appId?: string;
1847
2042
  }
1848
-
1849
- interface UploadSlot {
1850
- file: File;
1851
- progress: number;
1852
- status: 'uploading' | 'done' | 'error';
1853
- info?: FlyFileInfo;
1854
- error?: string;
2043
+ /** Disposable handle returned by the lookup registry. Idempotent `dispose()`. */
2044
+ interface LookupHandle {
2045
+ dispose(): void;
1855
2046
  }
1856
2047
  /**
1857
- * Multi-file upload with drag-drop, progress, and validation.
2048
+ * The wire envelope used by both the drag/drop surface and the imperative
2049
+ * {@link AgentActionBus}. Renderers narrow on `kind`; mismatches fall back to
2050
+ * `plainTextFallback`.
1858
2051
  *
1859
- * Usage:
1860
- * ```html
1861
- * <fly-file-upload
1862
- * [maxFiles]="5"
1863
- * [maxFileSizeBytes]="5242880"
1864
- * accept=".pdf,.docx,.xlsx"
1865
- * [(files)]="trend.attachments"
1866
- * sourceApp="circles"
1867
- * sourceEntityType="trend"
1868
- * (filesChanged)="onAttachmentsChanged($event)"
1869
- * />
1870
- * ```
2052
+ * The base fields (v1) describe **what** is being handed to the agent panel.
2053
+ * The v2 fields describe **how the agent should treat it** — `userMessage`
2054
+ * scopes the user-visible bubble, `systemContext` extends the system prompt,
2055
+ * `attachments` decorate the message with typed chips, and `mcpScope` hints
2056
+ * the agent toward a tool family. All v2 fields are optional so existing
2057
+ * v1 (drag/drop) payloads remain valid envelopes.
2058
+ *
2059
+ * Caps (see {@link AgentPayloadLimits}):
2060
+ * - JSON total 32 KB
2061
+ * - plainTextFallback 8 KB
2062
+ * - per-string field 4 KB
2063
+ * - userMessage 280 chars
2064
+ * - systemContext 32 entries × 4 KB per value, 8 KB total serialized
2065
+ * - attachments 4 entries, kind-dependent inner caps
2066
+ * - mcpScope.apis 5 prefixes × 128 chars
2067
+ *
2068
+ * The cap math is split per-section so an oversize attachment fails fast at the
2069
+ * attachment site instead of the whole envelope; field paths are dotted (see
2070
+ * {@link AgentPayloadValidationResult}).
1871
2071
  */
1872
- declare class FlyFileUploadComponent {
1873
- private http;
1874
- maxFiles: _angular_core.InputSignal<number>;
1875
- maxFileSizeBytes: _angular_core.InputSignal<number>;
1876
- accept: _angular_core.InputSignal<string>;
1877
- sourceApp: _angular_core.InputSignal<string>;
1878
- sourceEntityType: _angular_core.InputSignal<string | null>;
1879
- sourceEntityId: _angular_core.InputSignal<string | null>;
1880
- /** Optional: provide file IDs to auto-fetch metadata for pre-existing files (edit mode). */
1881
- existingFileIds: _angular_core.InputSignal<string[] | null>;
1882
- /** Two-way model for completed file metadata. */
1883
- files: _angular_core.ModelSignal<FlyFileInfo[]>;
1884
- filesChanged: _angular_core.OutputEmitterRef<FlyFileInfo[]>;
1885
- error: _angular_core.WritableSignal<string | null>;
1886
- dragging: _angular_core.WritableSignal<boolean>;
1887
- slots: _angular_core.WritableSignal<UploadSlot[]>;
1888
- /** Pre-existing files loaded from the entity (before any new uploads this session). */
1889
- existingFiles: _angular_core.WritableSignal<FlyFileInfo[]>;
1890
- fileInput: _angular_core.Signal<ElementRef<HTMLInputElement> | undefined>;
1891
- constructor();
1892
- allSlots: _angular_core.Signal<UploadSlot[]>;
1893
- canAddMore: _angular_core.Signal<boolean>;
1894
- limitHint: _angular_core.Signal<string>;
1895
- triggerFileInput(): void;
1896
- onDragOver(e: DragEvent): void;
1897
- onDragLeave(e: DragEvent): void;
1898
- onDrop(e: DragEvent): void;
1899
- onFilesSelected(e: Event): void;
1900
- removeSlot(slot: UploadSlot): void;
1901
- removeExisting(f: FlyFileInfo): void;
1902
- iconFor(slot: UploadSlot): string;
1903
- iconForInfo(f: FlyFileInfo): string;
1904
- formatFileSize(bytes: number): string;
1905
- private processFiles;
1906
- private uploadFile;
1907
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<FlyFileUploadComponent, never>;
1908
- 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>;
2072
+ interface AgentDragPayload<T = unknown> {
2073
+ /** Domain-stable kind, e.g. `circles.trend`. */
2074
+ readonly kind: string;
2075
+ /** Originating appId. Must match an entry in the host's app registry. */
2076
+ readonly appId: string;
2077
+ /** Frozen format version. Accepted: 1 or {@link AGENT_PAYLOAD_VERSION} (2). */
2078
+ readonly version: number;
2079
+ /** Domain object. Renderers narrow on `kind`. */
2080
+ readonly payload: T;
2081
+ /** Plain-text fallback written to the dataTransfer alongside the typed MIME. */
2082
+ readonly plainTextFallback: string;
2083
+ /** Optional command ids to highlight when this payload is dropped. */
2084
+ readonly suggestedCommandIds?: readonly string[];
2085
+ /**
2086
+ * Short, locale-resolved string the dispatcher wants shown in the user's
2087
+ * chat bubble. The agent panel uses it as the visible message text; when
2088
+ * absent, the panel falls back to a generic per-verb default
2089
+ * (e.g. "Tell me more about this"). Cap 280 chars — chip-sized, not essay.
2090
+ *
2091
+ * This is the ONLY field that should ever surface to the user verbatim.
2092
+ * Everything else (systemContext, attachment bodies, mcpScope) is wire-only.
2093
+ */
2094
+ readonly userMessage?: string;
2095
+ /**
2096
+ * Flat key→string facts the dispatcher wants injected into the agent's
2097
+ * system prompt for this turn. Keys are dot-namespaced (e.g.
2098
+ * `chart.name`, `chart.type`, `chart.dimension`) to keep the model's
2099
+ * mental schema flat and grep-friendly. Values are strings — booleans,
2100
+ * numbers, and dates must be pre-serialized at the call site so the
2101
+ * dispatcher owns the formatting (timezone, locale, number style).
2102
+ *
2103
+ * Cap: 32 entries, 4 KB per value, 8 KB total when serialized.
2104
+ *
2105
+ * NOT user-visible. The agent panel may transiently embed this as an
2106
+ * `[Internal context]` block in the wire content while the backend
2107
+ * learns to consume the dedicated field, but never renders it in the
2108
+ * user bubble.
2109
+ */
2110
+ readonly systemContext?: Readonly<Record<string, string>>;
2111
+ /**
2112
+ * Typed attachments rendered as a chip strip under the user's outgoing
2113
+ * message bubble. Each entry has a `kind` discriminator and a `label`
2114
+ * (locale-resolved by the dispatcher). v2 ships `json` + `text`;
2115
+ * `image` and `file` are reserved — their interfaces are stable so
2116
+ * future callers don't need a contract bump, but the panel may render
2117
+ * a generic chip for them until per-kind renderers land.
2118
+ *
2119
+ * Cap: 4 entries per envelope. Per-kind body caps:
2120
+ * - json: 16 KB serialized
2121
+ * - text: 8 KB UTF-8
2122
+ * - image / file: dataUrl ≤ 32 KB (small previews; large media stays in
2123
+ * the files-manager and is referenced by id)
2124
+ */
2125
+ readonly attachments?: readonly AgentEnvelopeAttachment[];
2126
+ /**
2127
+ * Advisory MCP scope. The agent service injects these prefixes into the
2128
+ * system prompt as a tool-selection hint ("prefer tools matching
2129
+ * `dashboard.reports.*` for this turn") — NOT a hard filter. The agent
2130
+ * remains free to pick any tool; this just biases the first guess so a
2131
+ * dashboard explain doesn't waste a tool-call probing Notes APIs first.
2132
+ *
2133
+ * Cap: 5 prefixes × 128 chars. Prefixes should match gateway-aggregated
2134
+ * OpenAPI tag/path roots so they line up with the names the MCP server
2135
+ * exposes — see `src/backend/gateway` Swagger aggregation + the dynamic
2136
+ * loader in `src/backend/mcp-server`.
2137
+ */
2138
+ readonly mcpScope?: AgentMcpScope;
2139
+ /**
2140
+ * Optional deep-link route the originating app can use to re-open the
2141
+ * source object. When set, payload chips (and any other renderer that
2142
+ * surfaces the envelope to the user) become clickable — clicking calls
2143
+ * `ShellLauncherService.launch({ appId, route: deepLinkRoute })` so the
2144
+ * target app opens / focuses and navigates to the originating object.
2145
+ *
2146
+ * Shape constraints (mirror `DeepLinkService.isValidRoute`):
2147
+ * - starts with `/`
2148
+ * - ≤ {@link AgentPayloadLimits.maxDeepLinkRouteBytes} bytes (default
2149
+ * 1024) — matches the route limit on the wider shell deep-link
2150
+ * contract so this field can be handed straight to the launcher.
2151
+ * - no `..` segments
2152
+ * - no `//` runs
2153
+ * - no scheme-like prefixes (`/javascript:`, `/data:`, `/http:`, `/https:`)
2154
+ *
2155
+ * The DS validator enforces only the byte cap — full route syntax
2156
+ * validation is owned by the shell side (`DeepLinkService`) because the
2157
+ * DS package is shell-agnostic and shouldn't grow a second copy of the
2158
+ * URL grammar. Apps building envelopes are expected to stamp routes that
2159
+ * match their own internal route schema (e.g. dashboard publishes
2160
+ * `/reports/{id}` and `/custom/{id}`); see `skills/cross-app-deep-linking.md`.
2161
+ *
2162
+ * Backwards-compat: absent on v1 payloads and on v2 payloads built
2163
+ * before this field was added. Persisted JSONB chips without the field
2164
+ * remain non-clickable; new chips light up automatically.
2165
+ */
2166
+ readonly deepLinkRoute?: string;
1909
2167
  }
1910
-
1911
2168
  /**
1912
- * Agent input contracts.
1913
- *
1914
- * These types define the wire and DI surface for the new `<fly-agent-input>` orchestrator
1915
- * (Phase 2+). Phase 1 ships only the contracts: payload envelope, command/drop registry
1916
- * shapes, and chip-host inputs. The concrete components consume them later.
1917
- *
1918
- * Design rules:
1919
- * - All fields are `readonly` — the registries store these in signal stores and we never
1920
- * want a host mutating after registration. Hosts construct fresh objects to update.
1921
- * - The discriminated kinds (`scope`, `mode`, `kind`) carry the entire variance — no
1922
- * boolean flags. New variants extend the union without breaking existing consumers.
1923
- * - The `Type<AgentChipHostInputs<T>>` shape is intentional: chip components declare
1924
- * `payload`, `mode`, optional `onRemove` as Angular `input()` signals; the registry
1925
- * wires them via `NgComponentOutlet` inputs in the consumer. The component reference
1926
- * itself never leaks across the federation boundary by value — only by class identity.
2169
+ * Canonical name for the bus-side envelope. v2 callers should reference this
2170
+ * over {@link AgentDragPayload} for clarity — the underlying shape is
2171
+ * identical, but the name signals "this is going to the agent, not to a
2172
+ * drop zone." The alias is intentional: one wire shape, two semantic uses.
1927
2173
  */
1928
- /** Frozen MIME used by `flyAgentDraggable` and the drop-zone reader. Never change without a DS major. */
1929
- declare const AGENT_DRAG_MIME: "application/x-fly-agent-payload+json";
2174
+ type AgentMessageEnvelope<T = unknown> = AgentDragPayload<T>;
1930
2175
  /**
1931
- * Frozen payload envelope version.
2176
+ * Typed attachment discriminator for {@link AgentDragPayload.attachments}.
1932
2177
  *
1933
- * v1minimal drag payload: kind / appId / version / payload / plainTextFallback /
1934
- * suggestedCommandIds. Still used by the drag/drop surface.
2178
+ * - `json` structured data the panel renders as a "code-ish" chip the
2179
+ * user can expand. Used for chart snapshots, query results, etc.
2180
+ * - `text` — short utterance / excerpt with optional MIME. Used when the
2181
+ * dispatcher wants the chip to preview a note paragraph, log line,
2182
+ * code snippet, etc.
2183
+ * - `image` / `file` — reserved. Stable interface; renderers added per
2184
+ * downstream caller (the panel may fall back to a generic icon-chip).
1935
2185
  *
1936
- * v2bus envelope ({@link AgentMessageEnvelope}). Adds optional `userMessage`,
1937
- * `systemContext`, `attachments`, `mcpScope` so a dispatcher can give the agent
1938
- * rich context without polluting the user-visible message bubble. v2 is a
1939
- * superset of v1 — every v1 payload is a valid v2 payload — so the version
1940
- * number ratchets forward without breaking existing callers.
2186
+ * Every kind carries `label` that's what shows on the chip face and what
2187
+ * a11y trees announce.
1941
2188
  */
1942
- declare const AGENT_PAYLOAD_VERSION: 2;
2189
+ type AgentEnvelopeAttachment = {
2190
+ readonly kind: 'json';
2191
+ readonly label: string;
2192
+ readonly json: unknown;
2193
+ } | {
2194
+ readonly kind: 'text';
2195
+ readonly label: string;
2196
+ readonly text: string;
2197
+ readonly mimeType?: string;
2198
+ } | {
2199
+ readonly kind: 'image';
2200
+ readonly label: string;
2201
+ /** `data:` URL — small previews only. Large media stays in files-manager. */
2202
+ readonly dataUrl: string;
2203
+ readonly mimeType: string;
2204
+ } | {
2205
+ readonly kind: 'file';
2206
+ readonly label: string;
2207
+ readonly dataUrl: string;
2208
+ readonly mimeType: string;
2209
+ readonly bytes: number;
2210
+ };
2211
+ /** Advisory tool-selection hint for {@link AgentDragPayload.mcpScope}. */
2212
+ interface AgentMcpScope {
2213
+ /**
2214
+ * Prefixes of gateway-aggregated OpenAPI tags / path roots — e.g.
2215
+ * `dashboard.reports`, `notes.documents`. The agent service treats these
2216
+ * as a soft preference, not a hard filter.
2217
+ */
2218
+ readonly apis: readonly string[];
2219
+ }
1943
2220
  /**
1944
- * Versions accepted by the validator. v1 payloads (the drag/drop surface) remain valid;
1945
- * v2 adds the optional bus-envelope fields. Renderers narrow on `version` when they need
1946
- * to.
2221
+ * Where a chip is being rendered. `inline` = inside the input chip tray (removable);
2222
+ * `message` = embedded in a sent message bubble (not removable).
1947
2223
  */
1948
- declare const SUPPORTED_AGENT_PAYLOAD_VERSIONS: readonly number[];
2224
+ type AgentDropChipMode = 'inline' | 'message';
1949
2225
  /**
1950
- * Where a command surfaces. `'global'` = always offered. `{ appId }` = offered only when
1951
- * the host's live `liveAppIds` set (passed to {@link AgentCommandRegistry.visible}) contains
1952
- * that id. This lets a remote register its slash command at boot but only have it appear
1953
- * in the palette while at least one of the remote's windows is open.
2226
+ * Public input shape for chip-renderer components. Components declare matching
2227
+ * `input()` signals; the registry wires them via `NgComponentOutlet`.
1954
2228
  */
1955
- type AgentCommandScope = 'global' | {
1956
- readonly appId: string;
1957
- };
2229
+ interface AgentChipHostInputs<T = unknown> {
2230
+ payload: AgentDragPayload<T>;
2231
+ mode: AgentDropChipMode;
2232
+ /** Called when the user clicks the chip's remove control (only in inline mode). */
2233
+ onRemove?: () => void;
2234
+ }
1958
2235
  /**
1959
- * A slash command offered by the agent input palette. Commands are deliberately shallow
1960
- * descriptors the host (shell) decides what happens on Send. The descriptor's role is
1961
- * to make the palette row renderable (icon, label, kbd hint, app badge) and matchable
1962
- * (id, aliases, drop-kind suggestions) without coupling DS to any business logic.
2236
+ * Keyboard-alternative draggable item. Hosts publish these via
2237
+ * {@link AgentDropRegistry.publishDraggables} so the "Attach from app…" menu can offer
2238
+ * them when pointer drag isn't available.
1963
2239
  */
1964
- interface AgentCommand {
1965
- /** Stable id, kebab-case. Becomes the slash text after `/`, e.g. `/analyze-trend`. */
2240
+ interface AgentDraggableItem<T = unknown> {
2241
+ /** Stable id within its app. Used as a list key in the kbd menu. */
1966
2242
  readonly id: string;
1967
- /** i18n key for the visible label, e.g. `agent.command.analyze_trend.label`. */
1968
2243
  readonly labelKey: string;
1969
- /** i18n key for an optional sublabel / description shown beneath the label. */
1970
- readonly descriptionKey?: string;
1971
- /** PrimeIcons class, e.g. `pi-chart-line`. */
1972
2244
  readonly icon?: string;
1973
- /** App badge label key appears as a small tag, e.g. `agent.command.app_badge.circles`. */
1974
- readonly appBadgeKey?: string;
1975
- /** Optional kbd hint i18n key. */
1976
- readonly kbdHintKey?: string;
1977
- /** When the command is keyword-matched against drop payload kinds, list those kinds here. */
1978
- readonly suggestForDropKinds?: readonly string[];
1979
- /** Extra match terms beyond id + label, used by the fuzzy filter. */
1980
- readonly aliases?: readonly string[];
1981
- /** When `'send'`, the command is inserted as a bound prefix and executed on Send. */
1982
- readonly executeOn: 'send';
1983
- /** Optional client-side gate. Return false to hide the command in this scope. */
1984
- readonly isVisible?: () => boolean;
1985
- }
1986
- /** What hosts pass to {@link AgentCommandRegistry.register}. Adds the scope to {@link AgentCommand}. */
1987
- interface AgentCommandRegistration extends AgentCommand {
1988
- readonly scope: AgentCommandScope;
2245
+ /** Builds the payload the moment the user picks the item. */
2246
+ build(): AgentDragPayload<T>;
1989
2247
  }
1990
- /** Disposable handle returned by {@link AgentCommandRegistry.register}. Idempotent `dispose()`. */
1991
- interface AgentCommandHandle {
1992
- dispose(): void;
2248
+ /** Registry input shape for binding a chip-renderer component to a kind+appId pair. */
2249
+ interface AgentDropRendererRegistration<T = unknown> {
2250
+ readonly kind: string;
2251
+ readonly appId: string;
2252
+ readonly component: Type<AgentChipHostInputs<T>>;
1993
2253
  }
1994
2254
  /**
1995
- * How a lookup fetches candidate entities. The picker calls the app's existing
1996
- * authenticated REST search endpoint (the same one the agent's MCP `*_list_brief`
1997
- * tool wraps) through the shell's HttpClient gateway routing + auth
1998
- * interceptor apply. We deliberately do NOT route typeahead through MCP (agent-
1999
- * shaped, agent-auth) or the dataset executor (aggregation-shaped, no fulltext).
2000
- *
2001
- * Field mapping is declarative because entities differ: Circles trends/signals
2002
- * expose `/brief` endpoints returning `{ id, title, status }`, while scenarios
2003
- * have no brief variant and return full objects with `titleEn` / `titleAr`. The
2004
- * `displayField` / `secondaryField` indirection absorbs that per-entity skew so
2005
- * one picker component serves them all.
2255
+ * Caps applied by {@link validateAgentPayload} / {@link trimAgentPayload}. The defaults
2256
+ * trade off "fits comfortably in a single MQ frame" against "covers a richly-populated
2257
+ * trend or note card". Hosts may pass a partial override.
2006
2258
  */
2007
- interface LookupSearch {
2008
- /**
2009
- * Relative REST path the picker GETs, e.g. `/api/circles/trends/brief`. Must
2010
- * be a relative path (no scheme/host) the SSRF guard at onboard time (when
2011
- * the descriptor is manifest-backed) and the picker both reject absolute URLs.
2012
- */
2013
- readonly endpoint: string;
2014
- /** Query param carrying the typed text, e.g. `search`. */
2015
- readonly queryParam: string;
2016
- /** Static query params merged into every request, e.g. `{ pageSize: '10' }`. */
2017
- readonly extraParams?: Readonly<Record<string, string>>;
2018
- /** Response-item field holding the entity id. Default `id`. */
2019
- readonly idField?: string;
2020
- /** Response-item field holding the display label, e.g. `title` / `titleEn`. */
2021
- readonly displayField: string;
2022
- /** Optional response-item field for the chip's secondary line (status, category). */
2023
- readonly secondaryField?: string;
2259
+ interface AgentPayloadLimits {
2260
+ /** Cap on the JSON.stringify(envelope) byte length. Default 32 KB. */
2261
+ readonly maxJsonBytes: number;
2262
+ /** Cap on the plainTextFallback byte length. Default 8 KB. */
2263
+ readonly maxPlainTextFallbackBytes: number;
2264
+ /** Cap on any single string field inside payload (recursive). Default 4 KB. */
2265
+ readonly maxStringFieldBytes: number;
2266
+ /** Cap on `userMessage` UTF-8 byte length. Default 280 chars (~1.1 KB). */
2267
+ readonly maxUserMessageBytes: number;
2268
+ /** Max entries in `systemContext`. Default 32. */
2269
+ readonly maxSystemContextEntries: number;
2270
+ /** Cap on any single systemContext value's UTF-8 byte length. Default 4 KB. */
2271
+ readonly maxSystemContextValueBytes: number;
2272
+ /** Cap on the full JSON.stringify(systemContext). Default 8 KB. */
2273
+ readonly maxSystemContextJsonBytes: number;
2274
+ /** Max attachments per envelope. Default 4. */
2275
+ readonly maxAttachments: number;
2276
+ /** Cap on a `json` attachment's serialized body. Default 16 KB. */
2277
+ readonly maxAttachmentJsonBytes: number;
2278
+ /** Cap on a `text` attachment's body bytes. Default 8 KB. */
2279
+ readonly maxAttachmentTextBytes: number;
2280
+ /** Cap on an `image` / `file` attachment's dataUrl bytes. Default 32 KB. */
2281
+ readonly maxAttachmentDataUrlBytes: number;
2282
+ /** Max prefixes in `mcpScope.apis`. Default 5. */
2283
+ readonly maxMcpScopeApis: number;
2284
+ /** Cap on any single mcpScope prefix string. Default 128 chars. */
2285
+ readonly maxMcpScopeApiBytes: number;
2024
2286
  /**
2025
- * Dotted path to the results array within the response body when it is
2026
- * wrapped, e.g. `items` for `{ items: [...], total }`. Omit when the response
2027
- * body IS the array.
2287
+ * Cap on `deepLinkRoute` UTF-8 byte length. Default 1024 bytes matches
2288
+ * the route limit on `DeepLinkService.isValidRoute` so this field can be
2289
+ * handed straight to the shell launcher without a second resize.
2028
2290
  */
2029
- readonly resultsPath?: string;
2291
+ readonly maxDeepLinkRouteBytes: number;
2292
+ }
2293
+ declare const DEFAULT_AGENT_PAYLOAD_LIMITS: AgentPayloadLimits;
2294
+ /**
2295
+ * Stable failure reasons emitted by {@link validateAgentPayload}.
2296
+ * - `invalid_version` — `version` !== {@link AGENT_PAYLOAD_VERSION}.
2297
+ * - `invalid_kind` — `kind` is empty / not a string.
2298
+ * - `field_too_large` — a string field inside `payload` exceeds `maxStringFieldBytes`.
2299
+ * - `fallback_too_large` — `plainTextFallback` exceeds `maxPlainTextFallbackBytes`.
2300
+ * - `json_too_large` — the full JSON.stringify(envelope) exceeds `maxJsonBytes`.
2301
+ */
2302
+ type AgentPayloadValidationResult = {
2303
+ readonly ok: true;
2304
+ } | {
2305
+ readonly ok: false;
2306
+ 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';
2307
+ /** Dotted property-access path to the offending field, e.g. `payload.title` or `payload.tags[2]`. NOT RFC 6901 JSON Pointer. */
2308
+ readonly fieldPath?: string;
2309
+ readonly actualBytes?: number;
2310
+ readonly limitBytes?: number;
2311
+ };
2312
+
2313
+ /**
2314
+ * Emitted by {@link EntityLookupComponent} when the user picks an entity that
2315
+ * resolves to an in-app deep link — everything a consumer needs to insert a
2316
+ * clickable `flyos:` link into an editor or message, without touching the
2317
+ * lookup registry itself.
2318
+ */
2319
+ interface EntityLinkSelection {
2320
+ /** The entity's display title — the link's visible text. */
2321
+ readonly label: string;
2322
+ /** Dotted `<appId>.<entity>` kind token (the `flyos:` host segment). */
2323
+ readonly kind: string;
2324
+ /** The entity id. */
2325
+ readonly id: string;
2326
+ /** Owning app id. */
2327
+ readonly appId: string;
2328
+ /** Resolved in-app route, e.g. `/trends/<id>`. */
2329
+ readonly route: string;
2330
+ /** Full `flyos:<appId>.<entity>/<id>` deep-link href. */
2331
+ readonly href: string;
2332
+ }
2333
+
2334
+ /**
2335
+ * Shared floating entity typeahead — the `/lookup` picker promoted out of the
2336
+ * agent composer into the design-system so any app (agent composer, notes,
2337
+ * task comments, federated remotes) can let a user find an entity and act on
2338
+ * it. Editor-agnostic: it emits a {@link LookupResult} ({@link pick}) and,
2339
+ * when the entity resolves to a deep link, an {@link EntityLinkSelection}
2340
+ * ({@link entityLinkSelected}) — the consumer decides whether to make a ref
2341
+ * chip, insert a `flyos:` link into an editor, etc.
2342
+ *
2343
+ * Two-stage cascade:
2344
+ * - **Stage 1 — entity**: a filterable autocomplete of the offered entities.
2345
+ * Skipped when there's one entity or `initialEntity` already names one.
2346
+ * - **Stage 2 — search**: a debounced typeahead against the chosen entity's
2347
+ * search endpoint, with a breadcrumb back to stage 1.
2348
+ *
2349
+ * The HTTP call goes through the host's `HttpClient` so the gateway routing +
2350
+ * auth interceptor apply — the same path the MCP `*_list_brief` tools wrap,
2351
+ * but user-authenticated. The "exposed by app" badge resolves names via the
2352
+ * optional {@link LOOKUP_APP_NAME_RESOLVER} the host provides (the DS has no
2353
+ * app registry); absent it, the badge falls back to `appBadgeKey`.
2354
+ */
2355
+ declare class EntityLookupComponent implements OnInit, OnDestroy {
2356
+ private readonly http;
2357
+ private readonly i18n;
2358
+ private readonly host;
2359
+ private readonly lookupRegistry;
2360
+ /** Host-provided appId → {id,name} adapter for the "exposed by app" badge.
2361
+ * The DS has no app registry; the shell (and remotes) provide APP_LOOKUP.
2362
+ * Optional — absent, the badge falls back to a descriptor's appBadgeKey. */
2363
+ private readonly appLookup;
2364
+ /** Entities the picker may search — already filtered to the live-app scope
2365
+ * by the caller. Empty renders a "nothing to look up" hint. */
2366
+ readonly descriptors: _angular_core.InputSignal<readonly LookupDescriptor[]>;
2367
+ /** Entity pre-selected (e.g. from `/lookup <entity>`). Ignored when it
2368
+ * doesn't match any descriptor (falls back to the first). */
2369
+ readonly initialEntity: _angular_core.InputSignal<string | undefined>;
2370
+ /** Query text pre-seeded (e.g. from `/lookup <entity> <query>`). */
2371
+ readonly initialQuery: _angular_core.InputSignal<string>;
2372
+ /** Per-instance listbox id so `aria-controls` / `aria-activedescendant`
2373
+ * resolve unambiguously when multiple panels mount. */
2374
+ readonly listboxId: _angular_core.InputSignal<string>;
2375
+ /** Open direction. `'up'` (default) suits a bottom-anchored composer (the
2376
+ * agent input); `'down'` suits a top-anchored toolbar button (notes / task
2377
+ * comments) — the panel then anchors to the host's positioned parent (the
2378
+ * button wrapper) and opens below it with a fixed width. */
2379
+ readonly placement: _angular_core.InputSignal<"up" | "down" | "above">;
2380
+ /** Raw pick — every consumer gets this (agent ref chips, etc.). */
2381
+ readonly pick: _angular_core.OutputEmitterRef<LookupResult>;
2382
+ /** Deep-link selection — emitted ONLY when the picked entity resolves to a
2383
+ * route via the lookup registry (so the consumer never gets a dead link).
2384
+ * Editors bind this to insert a `flyos:` anchor. */
2385
+ readonly entityLinkSelected: _angular_core.OutputEmitterRef<EntityLinkSelection>;
2386
+ readonly dismiss: _angular_core.OutputEmitterRef<void>;
2387
+ /** Which cascade stage is active: pick an entity, then search within it. */
2388
+ readonly stage: _angular_core.WritableSignal<"search" | "entity">;
2389
+ /** entity key of the descriptor currently being searched. */
2390
+ readonly activeEntity: _angular_core.WritableSignal<string | null>;
2391
+ /** In stage 1 this filters the entity list; in stage 2 it's the search text. */
2392
+ readonly query: _angular_core.WritableSignal<string>;
2393
+ readonly results: _angular_core.WritableSignal<readonly LookupResult[]>;
2394
+ readonly loading: _angular_core.WritableSignal<boolean>;
2395
+ /** i18n key for an inline error (network / bad endpoint); null when clear. */
2396
+ readonly errorKey: _angular_core.WritableSignal<string | null>;
2397
+ readonly activeIndex: _angular_core.WritableSignal<number>;
2398
+ /** Query stashed when no entity matched, so it can seed the search field the
2399
+ * moment the user picks an entity. One-shot. */
2400
+ private _seedQuery;
2401
+ /** The descriptor matching {@link activeEntity}, or null. */
2402
+ readonly activeDescriptor: _angular_core.Signal<LookupDescriptor | null>;
2403
+ /** Stage-1 entity options, narrowed by the typed filter. Touches
2404
+ * `i18n.version()` so a locale switch re-resolves the label match. */
2405
+ readonly filteredEntities: _angular_core.Signal<readonly LookupDescriptor[]>;
2406
+ /** Size of the list the keyboard currently navigates (entities vs results). */
2407
+ readonly listSize: _angular_core.Signal<number>;
2408
+ /** Show the breadcrumb / back affordance only when there's a real choice of
2409
+ * entity to step back to. */
2410
+ readonly showBack: _angular_core.Signal<boolean>;
2411
+ /** Placeholder reflects the active stage. */
2412
+ readonly searchPlaceholderKey: _angular_core.Signal<string>;
2413
+ private _debounceTimer;
2414
+ private _searchSub;
2415
+ private readonly searchEl?;
2416
+ constructor();
2417
+ ngOnInit(): void;
2418
+ ngOnDestroy(): void;
2419
+ optionId(index: number): string;
2420
+ readonly activeDescendant: _angular_core.Signal<string>;
2421
+ private _clampedIndex;
2422
+ onQueryInput(value: string): void;
2423
+ onSelectEntity(entity: string): void;
2424
+ goBackToEntity(): void;
2425
+ onRowClick(row: LookupResult): void;
2426
+ onRowHover(index: number): void;
2427
+ /**
2428
+ * Single pick exit. Emits the raw {@link pick} for every consumer, AND —
2429
+ * when the entity resolves to a deep-link route via the registry — an
2430
+ * {@link entityLinkSelected} carrying the `flyos:` href. Resolution failures
2431
+ * (unknown entity / app mismatch / owning app not installed / no
2432
+ * `deepLinkRoute`) simply omit the deep-link event: editor consumers get
2433
+ * nothing to insert rather than a dead link, while the raw `pick` path
2434
+ * (agent ref chips) still fires.
2435
+ */
2436
+ private _selectRow;
2437
+ onKeydown(ev: KeyboardEvent): void;
2438
+ onDocumentMouseDown(ev: MouseEvent): void;
2439
+ onDocumentEscape(): void;
2440
+ private _scheduleSearch;
2441
+ private _clearTimer;
2442
+ private _runSearch;
2443
+ private _mapResults;
2444
+ private _extractArray;
2445
+ private _focusSearch;
2446
+ entityLabel(desc: LookupDescriptor): string;
2447
+ readonly activeEntityLabel: _angular_core.Signal<string>;
2448
+ /**
2449
+ * Display name of the app exposing this descriptor, for the "exposed by …"
2450
+ * badge. Resolution order: host-provided {@link LOOKUP_APP_NAME_RESOLVER}
2451
+ * (keyed by `descriptor.appId`) → descriptor `appBadgeKey` (literal i18n
2452
+ * key, for entities not mapped to a single shell app) → '' (no badge).
2453
+ */
2454
+ appLabel(desc: LookupDescriptor): string;
2455
+ readonly activeAppLabel: _angular_core.Signal<string>;
2456
+ /** Per-row source-app label for stage-2 rows. Resolves {@link LookupResult.appId}
2457
+ * through the host resolver. '' when the row carries no `appId`, the resolver
2458
+ * is absent / doesn't know it, or it duplicates {@link activeAppLabel}. */
2459
+ rowAppLabel(row: LookupResult): string;
2460
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<EntityLookupComponent, never>;
2461
+ 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>;
2462
+ }
2463
+
2464
+ /**
2465
+ * Host-provided handler that navigates to a resolved in-app entity deep link
2466
+ * when the user clicks a `flyos:` anchor inside a {@link FlyMarkdownEditorComponent}.
2467
+ *
2468
+ * The design-system can RESOLVE a `flyos:<appId>.<entity>/<id>` href to a
2469
+ * `{ appId, route }` (via `AgentLookupRegistry`), but it cannot LAUNCH it — the
2470
+ * launcher lives in the host (the desktop shell's `ShellLauncherService`, or a
2471
+ * remote's own router). The host provides this token; when absent, a `flyos:`
2472
+ * click is a no-op (the link is non-routable in a bare browser anyway).
2473
+ */
2474
+ type EntityLinkLauncher = (target: {
2475
+ readonly appId: string;
2476
+ readonly route: string;
2477
+ readonly kind: string;
2478
+ readonly id: string;
2479
+ }) => void;
2480
+ declare const ENTITY_LINK_LAUNCHER: InjectionToken<EntityLinkLauncher>;
2481
+ /**
2482
+ * A toolbar control id, or `'|'` for a visual divider. `toolbar` accepts a
2483
+ * preset name or an explicit ordered list of these.
2484
+ */
2485
+ type MarkdownToolbarItem = 'undo' | 'redo' | 'h1' | 'h2' | 'h3' | 'bold' | 'italic' | 'underline' | 'strike' | 'code' | 'bulletList' | 'orderedList' | 'taskList' | 'blockquote' | 'codeBlock' | 'horizontalRule' | 'link' | 'entityLink' | '|';
2486
+ /** Named toolbar presets. `full` ≈ the notes editor; `compact` ≈ task comments. */
2487
+ type MarkdownToolbarPreset = 'full' | 'compact';
2488
+ declare const MARKDOWN_TOOLBAR_PRESETS: Record<MarkdownToolbarPreset, readonly MarkdownToolbarItem[]>;
2489
+
2490
+ /**
2491
+ * Shared rich-text/markdown editor — the single Tiptap-backed editor for FlyOS
2492
+ * apps (notes, task comments, admin) and Business Apps (Circles). Emits a
2493
+ * Markdown string via `ControlValueAccessor`, so it slots into reactive forms
2494
+ * or `[(ngModel)]` with no orchestration.
2495
+ *
2496
+ * Bakes in the platform's `flyos:` entity-deep-link contract: the Link mark
2497
+ * whitelists the `flyos` scheme (so authored/pasted deep links aren't blanked),
2498
+ * clicks on a resolvable `flyos:` anchor launch the owning app via the
2499
+ * host-provided {@link ENTITY_LINK_LAUNCHER}, and the optional "entity link"
2500
+ * toolbar button opens the shared {@link EntityLookupComponent} to insert one.
2501
+ */
2502
+ declare class FlyMarkdownEditorComponent implements ControlValueAccessor, OnDestroy {
2503
+ private readonly cdr;
2504
+ private readonly lookupRegistry;
2505
+ private readonly launcher;
2506
+ /** Toolbar preset name or an explicit ordered item list. */
2507
+ readonly toolbar: _angular_core.InputSignal<MarkdownToolbarPreset | readonly MarkdownToolbarItem[]>;
2508
+ /** Show the "insert in-app link" (entity-lookup) toolbar button. */
2509
+ readonly enableEntityLink: _angular_core.InputSignal<boolean>;
2510
+ /** Direction the entity-lookup dropdown opens. `down` (default) suits a
2511
+ * top toolbar (notes); `above` suits a bottom-anchored composer (task
2512
+ * comments) so the panel doesn't run off the viewport. */
2513
+ readonly entityLinkPlacement: _angular_core.InputSignal<"down" | "above">;
2514
+ readonly placeholder: _angular_core.InputSignal<string>;
2515
+ readonly readonly: _angular_core.InputSignal<boolean>;
2516
+ readonly ariaLabel: _angular_core.InputSignal<string>;
2517
+ /** Fired on Ctrl/Cmd+Enter (host can submit a comment, etc.). */
2518
+ readonly submitShortcut: _angular_core.OutputEmitterRef<void>;
2519
+ private onChange;
2520
+ private onTouched;
2521
+ private currentValue;
2522
+ readonly activeStates: _angular_core.WritableSignal<Record<string, boolean>>;
2523
+ readonly canUndo: _angular_core.WritableSignal<boolean>;
2524
+ readonly canRedo: _angular_core.WritableSignal<boolean>;
2525
+ readonly showLinkPopover: _angular_core.WritableSignal<boolean>;
2526
+ readonly linkInputValue: _angular_core.WritableSignal<string>;
2527
+ readonly showEntityLookup: _angular_core.WritableSignal<boolean>;
2528
+ readonly entityLookupDescriptors: _angular_core.Signal<readonly LookupDescriptor[]>;
2529
+ /** Resolved toolbar items (preset → array), entityLink stripped when disabled. */
2530
+ readonly toolbarItems: _angular_core.Signal<readonly MarkdownToolbarItem[]>;
2531
+ readonly editor: Editor;
2532
+ constructor();
2533
+ ngOnDestroy(): void;
2534
+ writeValue(value: string | null): void;
2535
+ registerOnChange(fn: (v: string) => void): void;
2536
+ registerOnTouched(fn: () => void): void;
2537
+ setDisabledState(isDisabled: boolean): void;
2538
+ /** Current markdown (same as the CVA value). */
2539
+ getMarkdown(): string;
2540
+ /** Current rendered HTML snapshot. */
2541
+ getHtml(): string;
2542
+ /** Focus the editor surface. */
2543
+ focus(): void;
2544
+ button(id: MarkdownToolbarItem): {
2545
+ icon: string;
2546
+ labelKey: string;
2547
+ } | null;
2548
+ /** Short visual label for buttons rendered as text (B / I / U / S / H1…). */
2549
+ textLabel(id: MarkdownToolbarItem): string | null;
2550
+ run(id: MarkdownToolbarItem): void;
2551
+ isActive(id: MarkdownToolbarItem): boolean;
2552
+ disabled(id: MarkdownToolbarItem): boolean;
2553
+ private refreshState;
2554
+ openLinkPopover(): void;
2555
+ onLinkInput(value: string): void;
2556
+ commitLink(): void;
2557
+ cancelLink(): void;
2558
+ onLinkKeydown(event: KeyboardEvent): void;
2559
+ toggleEntityLookup(): void;
2560
+ closeEntityLookup(): void;
2561
+ onEntityLinkSelected(sel: EntityLinkSelection): void;
2562
+ /** True (click handled) when a resolvable `flyos:` anchor was launched. */
2563
+ private handleFlyosClick;
2564
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<FlyMarkdownEditorComponent, never>;
2565
+ 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>;
2566
+ }
2567
+
2568
+ interface ContextMenuItem {
2569
+ id: string;
2570
+ label: string;
2571
+ icon: string;
2572
+ }
2573
+ interface ContextMenuSection {
2574
+ label?: string;
2575
+ items: ContextMenuItem[];
2576
+ }
2577
+ declare class ContextMenuComponent implements AfterViewInit, OnDestroy {
2578
+ private menuEl?;
2579
+ private readonly doc;
2580
+ private readonly hostEl;
2581
+ x: _angular_core.InputSignal<number>;
2582
+ y: _angular_core.InputSignal<number>;
2583
+ sections: _angular_core.InputSignal<ContextMenuSection[]>;
2584
+ action: _angular_core.OutputEmitterRef<string>;
2585
+ closed: _angular_core.OutputEmitterRef<void>;
2586
+ private menuWidth;
2587
+ private menuHeight;
2588
+ private previouslyFocused;
2589
+ clampedPos: _angular_core.Signal<{
2590
+ left: number;
2591
+ top: number;
2592
+ }>;
2593
+ ngAfterViewInit(): void;
2594
+ ngOnDestroy(): void;
2595
+ onAction(id: string): void;
2596
+ onClickOutside(event: MouseEvent): void;
2597
+ onEscape(): void;
2598
+ onContextMenu(event: MouseEvent): void;
2599
+ onKeydown(event: KeyboardEvent): void;
2600
+ private close;
2601
+ private getMenuItems;
2602
+ private focusItem;
2603
+ private restoreFocus;
2604
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<ContextMenuComponent, never>;
2605
+ 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>;
2606
+ }
2607
+
2608
+ declare enum MessageBoxButtons {
2609
+ OK = 0,
2610
+ OKCancel = 1,
2611
+ YesNo = 2,
2612
+ YesNoCancel = 3,
2613
+ RetryCancel = 4,
2614
+ AbortRetryIgnore = 5
2615
+ }
2616
+ declare enum MessageBoxIcon {
2617
+ None = 0,
2618
+ Information = 1,
2619
+ Warning = 2,
2620
+ Error = 3,
2621
+ Question = 4
2622
+ }
2623
+ declare enum DialogResult {
2624
+ None = 0,
2625
+ OK = 1,
2626
+ Cancel = 2,
2627
+ Yes = 3,
2628
+ No = 4,
2629
+ Retry = 5,
2630
+ Abort = 6,
2631
+ Ignore = 7
2632
+ }
2633
+ interface MessageBoxOptions {
2634
+ title: string;
2635
+ message: string;
2636
+ buttons?: MessageBoxButtons;
2637
+ icon?: MessageBoxIcon;
2030
2638
  }
2031
2639
  /**
2032
- * A lookupable entity offered by the `/lookup` palette. Registered by the owning
2033
- * app (a federation remote self-registers at boot, mirroring {@link AgentCommand})
2034
- * or, once manifest-backed, projected from the app's `lookups[]` manifest section.
2035
- *
2036
- * The descriptor is a shallow, business-logic-free descriptor: it tells the
2037
- * picker WHAT to search, WHERE it is offered, and HOW to map the response — the
2038
- * picker owns the typeahead UX, the shell owns the HTTP call.
2640
+ * Configuration for the "Don't ask again" checkbox rendered by
2641
+ * `showAcknowledged()`. The field is intentionally NOT part of the base
2642
+ * `MessageBoxOptions` so the type system enforces the rule
2643
+ * "checkbox ⇒ caller MUST use `showAcknowledged()`": the classic `show()`
2644
+ * entry point cannot accept this shape, eliminating the silent-discard
2645
+ * dark-pattern path where the user's choice was thrown away.
2039
2646
  */
2040
- interface LookupDescriptor {
2041
- /**
2042
- * Stable entity key, kebab/lower, e.g. `scenario`. Doubles as the `/lookup
2043
- * <entity>` sub-token and the group key the picked ref is grouped under when
2044
- * serialized for the agent.
2045
- */
2046
- readonly entity: string;
2047
- /** i18n key for the entity's display name in the picker / palette. */
2048
- readonly labelKey: string;
2049
- /** Optional PrimeIcons class for the picker row + chip. */
2050
- readonly icon?: string;
2051
- /**
2052
- * Route globs where this lookup is offered (matched against the shell's
2053
- * router url), e.g. `['/scenarios/*', '/trends/*']`. Omit / empty = offered
2054
- * everywhere the owning app is live.
2055
- */
2056
- readonly pages?: readonly string[];
2057
- /** How to fetch + map candidates. */
2058
- readonly search: LookupSearch;
2647
+ interface MessageBoxDontAskAgainConfig {
2648
+ /** i18n key for the checkbox label, e.g. 'agent.command.builtin.clear.dont_ask_again'. */
2649
+ labelKey: string;
2650
+ /** Initial checked state. Default false. */
2651
+ defaultChecked?: boolean;
2059
2652
  }
2060
- /** What hosts pass to the lookup registry. Adds the scope to {@link LookupDescriptor}. */
2061
- interface LookupRegistration extends LookupDescriptor {
2062
- /** Same scoping semantics as {@link AgentCommandScope}. */
2063
- readonly scope: AgentCommandScope;
2653
+ /**
2654
+ * Options narrowed to those carrying a `dontAskAgain` config — the only shape
2655
+ * accepted by `showAcknowledged()`.
2656
+ */
2657
+ interface MessageBoxOptionsWithAcknowledgement extends MessageBoxOptions {
2658
+ dontAskAgain: MessageBoxDontAskAgainConfig;
2064
2659
  }
2065
- /** One resolved row the picker returns once the user selects a candidate. */
2066
- interface LookupResult {
2067
- /** The entity kind (echoes {@link LookupDescriptor.entity}). */
2068
- readonly entity: string;
2069
- /** Selected entity id. */
2070
- readonly id: string;
2071
- /** Selected entity's display label. */
2072
- readonly label: string;
2073
- /** Optional secondary detail (status / category). */
2074
- readonly secondary?: string;
2660
+ interface MessageBoxButton {
2661
+ label: string;
2662
+ result: DialogResult;
2663
+ variant?: 'primary' | 'danger' | 'default';
2075
2664
  }
2076
- /** Disposable handle returned by the lookup registry. Idempotent `dispose()`. */
2077
- interface LookupHandle {
2078
- dispose(): void;
2665
+ /** Shape returned by `showAcknowledged()` — pairs the dialog result with the checkbox state. */
2666
+ interface DialogResultWithAcknowledgement {
2667
+ readonly result: DialogResult;
2668
+ readonly dontAskAgain: boolean;
2079
2669
  }
2080
- /**
2081
- * The wire envelope used by both the drag/drop surface and the imperative
2082
- * {@link AgentActionBus}. Renderers narrow on `kind`; mismatches fall back to
2083
- * `plainTextFallback`.
2084
- *
2085
- * The base fields (v1) describe **what** is being handed to the agent panel.
2086
- * The v2 fields describe **how the agent should treat it** — `userMessage`
2087
- * scopes the user-visible bubble, `systemContext` extends the system prompt,
2088
- * `attachments` decorate the message with typed chips, and `mcpScope` hints
2089
- * the agent toward a tool family. All v2 fields are optional so existing
2090
- * v1 (drag/drop) payloads remain valid envelopes.
2091
- *
2092
- * Caps (see {@link AgentPayloadLimits}):
2093
- * - JSON total 32 KB
2094
- * - plainTextFallback 8 KB
2095
- * - per-string field 4 KB
2096
- * - userMessage 280 chars
2097
- * - systemContext 32 entries × 4 KB per value, 8 KB total serialized
2098
- * - attachments 4 entries, kind-dependent inner caps
2099
- * - mcpScope.apis 5 prefixes × 128 chars
2100
- *
2101
- * The cap math is split per-section so an oversize attachment fails fast at the
2102
- * attachment site instead of the whole envelope; field paths are dotted (see
2103
- * {@link AgentPayloadValidationResult}).
2104
- */
2105
- interface AgentDragPayload<T = unknown> {
2106
- /** Domain-stable kind, e.g. `circles.trend`. */
2107
- readonly kind: string;
2108
- /** Originating appId. Must match an entry in the host's app registry. */
2109
- readonly appId: string;
2110
- /** Frozen format version. Accepted: 1 or {@link AGENT_PAYLOAD_VERSION} (2). */
2111
- readonly version: number;
2112
- /** Domain object. Renderers narrow on `kind`. */
2113
- readonly payload: T;
2114
- /** Plain-text fallback written to the dataTransfer alongside the typed MIME. */
2115
- readonly plainTextFallback: string;
2116
- /** Optional command ids to highlight when this payload is dropped. */
2117
- readonly suggestedCommandIds?: readonly string[];
2118
- /**
2119
- * Short, locale-resolved string the dispatcher wants shown in the user's
2120
- * chat bubble. The agent panel uses it as the visible message text; when
2121
- * absent, the panel falls back to a generic per-verb default
2122
- * (e.g. "Tell me more about this"). Cap 280 chars — chip-sized, not essay.
2123
- *
2124
- * This is the ONLY field that should ever surface to the user verbatim.
2125
- * Everything else (systemContext, attachment bodies, mcpScope) is wire-only.
2126
- */
2127
- readonly userMessage?: string;
2128
- /**
2129
- * Flat key→string facts the dispatcher wants injected into the agent's
2130
- * system prompt for this turn. Keys are dot-namespaced (e.g.
2131
- * `chart.name`, `chart.type`, `chart.dimension`) to keep the model's
2132
- * mental schema flat and grep-friendly. Values are strings — booleans,
2133
- * numbers, and dates must be pre-serialized at the call site so the
2134
- * dispatcher owns the formatting (timezone, locale, number style).
2135
- *
2136
- * Cap: 32 entries, 4 KB per value, 8 KB total when serialized.
2137
- *
2138
- * NOT user-visible. The agent panel may transiently embed this as an
2139
- * `[Internal context]` block in the wire content while the backend
2140
- * learns to consume the dedicated field, but never renders it in the
2141
- * user bubble.
2142
- */
2143
- readonly systemContext?: Readonly<Record<string, string>>;
2670
+ declare class MessageBoxService {
2671
+ private readonly i18n;
2672
+ readonly visible: _angular_core.WritableSignal<boolean>;
2673
+ readonly title: _angular_core.WritableSignal<string>;
2674
+ readonly message: _angular_core.WritableSignal<string>;
2675
+ readonly icon: _angular_core.WritableSignal<MessageBoxIcon>;
2676
+ readonly buttons: _angular_core.WritableSignal<MessageBoxButton[]>;
2144
2677
  /**
2145
- * Typed attachments rendered as a chip strip under the user's outgoing
2146
- * message bubble. Each entry has a `kind` discriminator and a `label`
2147
- * (locale-resolved by the dispatcher). v2 ships `json` + `text`;
2148
- * `image` and `file` are reserved — their interfaces are stable so
2149
- * future callers don't need a contract bump, but the panel may render
2150
- * a generic chip for them until per-kind renderers land.
2151
- *
2152
- * Cap: 4 entries per envelope. Per-kind body caps:
2153
- * - json: 16 KB serialized
2154
- * - text: 8 KB UTF-8
2155
- * - image / file: dataUrl ≤ 32 KB (small previews; large media stays in
2156
- * the files-manager and is referenced by id)
2678
+ * Active "Don't ask again" config populated only by `showAcknowledged()`.
2679
+ * `show()` callers cannot reach this signal because the type system rejects
2680
+ * `dontAskAgain` on the base `MessageBoxOptions`.
2157
2681
  */
2158
- readonly attachments?: readonly AgentEnvelopeAttachment[];
2682
+ readonly dontAskAgain: _angular_core.WritableSignal<MessageBoxDontAskAgainConfig | undefined>;
2159
2683
  /**
2160
- * Advisory MCP scope. The agent service injects these prefixes into the
2161
- * system prompt as a tool-selection hint ("prefer tools matching
2162
- * `dashboard.reports.*` for this turn") NOT a hard filter. The agent
2163
- * remains free to pick any tool; this just biases the first guess so a
2164
- * dashboard explain doesn't waste a tool-call probing Notes APIs first.
2165
- *
2166
- * Cap: 5 prefixes × 128 chars. Prefixes should match gateway-aggregated
2167
- * OpenAPI tag/path roots so they line up with the names the MCP server
2168
- * exposes — see `src/backend/gateway` Swagger aggregation + the dynamic
2169
- * loader in `src/backend/mcp-server`.
2684
+ * Component-side checkbox state. The component (`MessageBoxComponent`) wires
2685
+ * its own signal to this one; the service explicitly re-seeds it on every
2686
+ * `_open()` so reusing a constant `options` literal across two opens does
2687
+ * NOT leak the previous user's checkbox state through signal `===` dedupe.
2688
+ * Exposed for the component to read/write; not for general callers.
2170
2689
  */
2171
- readonly mcpScope?: AgentMcpScope;
2690
+ readonly dontAskAgainChecked: _angular_core.WritableSignal<boolean>;
2691
+ private resolver;
2692
+ show(options: MessageBoxOptions): Promise<DialogResult>;
2172
2693
  /**
2173
- * Optional deep-link route the originating app can use to re-open the
2174
- * source object. When set, payload chips (and any other renderer that
2175
- * surfaces the envelope to the user) become clickable clicking calls
2176
- * `ShellLauncherService.launch({ appId, route: deepLinkRoute })` so the
2177
- * target app opens / focuses and navigates to the originating object.
2178
- *
2179
- * Shape constraints (mirror `DeepLinkService.isValidRoute`):
2180
- * - starts with `/`
2181
- * - ≤ {@link AgentPayloadLimits.maxDeepLinkRouteBytes} bytes (default
2182
- * 1024) — matches the route limit on the wider shell deep-link
2183
- * contract so this field can be handed straight to the launcher.
2184
- * - no `..` segments
2185
- * - no `//` runs
2186
- * - no scheme-like prefixes (`/javascript:`, `/data:`, `/http:`, `/https:`)
2187
- *
2188
- * The DS validator enforces only the byte cap — full route syntax
2189
- * validation is owned by the shell side (`DeepLinkService`) because the
2190
- * DS package is shell-agnostic and shouldn't grow a second copy of the
2191
- * URL grammar. Apps building envelopes are expected to stamp routes that
2192
- * match their own internal route schema (e.g. dashboard publishes
2193
- * `/reports/{id}` and `/custom/{id}`); see `skills/cross-app-deep-linking.md`.
2194
- *
2195
- * Backwards-compat: absent on v1 payloads and on v2 payloads built
2196
- * before this field was added. Persisted JSONB chips without the field
2197
- * remain non-clickable; new chips light up automatically.
2694
+ * Opens a message box with a "Don't ask again" checkbox and resolves to both
2695
+ * the dialog result and the checkbox state. Throws when `options.dontAskAgain`
2696
+ * is missing — the checkbox config is mandatory for this entry point. The
2697
+ * compile-time signature already guarantees presence; the runtime check is
2698
+ * defense-in-depth for callers that bypass the type system via `as never`.
2198
2699
  */
2199
- readonly deepLinkRoute?: string;
2700
+ showAcknowledged(options: MessageBoxOptionsWithAcknowledgement): Promise<DialogResultWithAcknowledgement>;
2701
+ resolve(result: DialogResult, dontAskAgain?: boolean): void;
2702
+ private _open;
2703
+ private resolveButtons;
2704
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<MessageBoxService, never>;
2705
+ static ɵprov: _angular_core.ɵɵInjectableDeclaration<MessageBoxService>;
2200
2706
  }
2201
- /**
2202
- * Canonical name for the bus-side envelope. v2 callers should reference this
2203
- * over {@link AgentDragPayload} for clarity — the underlying shape is
2204
- * identical, but the name signals "this is going to the agent, not to a
2205
- * drop zone." The alias is intentional: one wire shape, two semantic uses.
2206
- */
2207
- type AgentMessageEnvelope<T = unknown> = AgentDragPayload<T>;
2208
- /**
2209
- * Typed attachment discriminator for {@link AgentDragPayload.attachments}.
2210
- *
2211
- * - `json` — structured data the panel renders as a "code-ish" chip the
2212
- * user can expand. Used for chart snapshots, query results, etc.
2213
- * - `text` — short utterance / excerpt with optional MIME. Used when the
2214
- * dispatcher wants the chip to preview a note paragraph, log line,
2215
- * code snippet, etc.
2216
- * - `image` / `file` — reserved. Stable interface; renderers added per
2217
- * downstream caller (the panel may fall back to a generic icon-chip).
2218
- *
2219
- * Every kind carries `label` — that's what shows on the chip face and what
2220
- * a11y trees announce.
2221
- */
2222
- type AgentEnvelopeAttachment = {
2223
- readonly kind: 'json';
2224
- readonly label: string;
2225
- readonly json: unknown;
2226
- } | {
2227
- readonly kind: 'text';
2228
- readonly label: string;
2229
- readonly text: string;
2230
- readonly mimeType?: string;
2231
- } | {
2232
- readonly kind: 'image';
2233
- readonly label: string;
2234
- /** `data:` URL — small previews only. Large media stays in files-manager. */
2235
- readonly dataUrl: string;
2236
- readonly mimeType: string;
2237
- } | {
2238
- readonly kind: 'file';
2239
- readonly label: string;
2240
- readonly dataUrl: string;
2241
- readonly mimeType: string;
2242
- readonly bytes: number;
2243
- };
2244
- /** Advisory tool-selection hint for {@link AgentDragPayload.mcpScope}. */
2245
- interface AgentMcpScope {
2707
+
2708
+ declare class MessageBoxComponent implements AfterViewInit {
2709
+ service: MessageBoxService;
2710
+ private elRef;
2711
+ readonly MessageBoxIcon: typeof MessageBoxIcon;
2712
+ readonly DialogResult: typeof DialogResult;
2713
+ /** Mirror of the service's `dontAskAgain` config so the template can read it directly. */
2714
+ readonly dontAskAgainConfig: _angular_core.Signal<_mohamedatia_fly_design_system.MessageBoxDontAskAgainConfig | undefined>;
2246
2715
  /**
2247
- * Prefixes of gateway-aggregated OpenAPI tags / path roots e.g.
2248
- * `dashboard.reports`, `notes.documents`. The agent service treats these
2249
- * as a soft preference, not a hard filter.
2716
+ * User-driven checkbox state, owned by the service and re-seeded on every
2717
+ * `_open()` so reusing a constant options literal cannot leak prior state.
2250
2718
  */
2251
- readonly apis: readonly string[];
2719
+ readonly dontAskAgainChecked: _angular_core.WritableSignal<boolean>;
2720
+ /**
2721
+ * Concatenated id list for the dialog's `aria-describedby`. Always includes
2722
+ * the message; appends the checkbox label id when the checkbox is rendered
2723
+ * so screen readers announce the checkbox as part of the description.
2724
+ */
2725
+ readonly ariaDescribedBy: _angular_core.Signal<"mb-message mb-dont-ask" | "mb-message">;
2726
+ private previouslyFocused;
2727
+ ngAfterViewInit(): void;
2728
+ onEscape(): void;
2729
+ onBackdropClick(): void;
2730
+ onButtonClick(result: DialogResult): void;
2731
+ onDontAskAgainToggle(ev: Event): void;
2732
+ iconClass(): string;
2733
+ private focusPrimaryButton;
2734
+ private restoreFocus;
2735
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<MessageBoxComponent, never>;
2736
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<MessageBoxComponent, "fly-message-box", never, {}, {}, never, never, true, never>;
2252
2737
  }
2738
+
2739
+ /** Full-bleed loading overlay for window content (shell) or embedded hosts. */
2740
+ declare class FlyBlockUiComponent {
2741
+ /** When false, the overlay is not rendered (host may use @if instead). */
2742
+ active: _angular_core.InputSignal<boolean>;
2743
+ /** i18n key for status text; empty uses `common.loading`. */
2744
+ messageKey: _angular_core.InputSignal<string>;
2745
+ readonly resolvedMessageKey: _angular_core.Signal<string>;
2746
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<FlyBlockUiComponent, never>;
2747
+ 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>;
2748
+ }
2749
+
2253
2750
  /**
2254
- * Where a chip is being rendered. `inline` = inside the input chip tray (removable);
2255
- * `message` = embedded in a sent message bubble (not removable).
2256
- */
2257
- type AgentDropChipMode = 'inline' | 'message';
2258
- /**
2259
- * Public input shape for chip-renderer components. Components declare matching
2260
- * `input()` signals; the registry wires them via `NgComponentOutlet`.
2751
+ * Metadata returned by Files Manager after a successful upload or metadata query.
2752
+ * Mirrors the `FileMetadataDto` shape from `GET /api/files/{id}` and `POST /api/files/upload`.
2261
2753
  */
2262
- interface AgentChipHostInputs<T = unknown> {
2263
- payload: AgentDragPayload<T>;
2264
- mode: AgentDropChipMode;
2265
- /** Called when the user clicks the chip's remove control (only in inline mode). */
2266
- onRemove?: () => void;
2754
+ interface FlyFileInfo {
2755
+ id: string;
2756
+ fileName: string;
2757
+ contentType: string;
2758
+ sizeBytes: number;
2759
+ sourceApp: string;
2760
+ sourceEntityType?: string;
2761
+ sourceEntityId?: string;
2762
+ uploadedByUserId?: string;
2763
+ correlationId?: string;
2764
+ isConfirmed: boolean;
2765
+ version: number;
2766
+ scanStatus: string;
2767
+ createdAt: string;
2768
+ folderId?: string;
2769
+ hasErrors: boolean;
2267
2770
  }
2771
+
2268
2772
  /**
2269
- * Keyboard-alternative draggable item. Hosts publish these via
2270
- * {@link AgentDropRegistry.publishDraggables} so the "Attach from app…" menu can offer
2271
- * them when pointer drag isn't available.
2773
+ * Image upload component with built-in cropperjs cropping modal.
2774
+ *
2775
+ * Usage:
2776
+ * ```html
2777
+ * <fly-image-upload
2778
+ * [aspectRatio]="16/9"
2779
+ * [currentImageId]="trend.coverImageId"
2780
+ * sourceApp="circles"
2781
+ * sourceEntityType="trend"
2782
+ * (uploaded)="onImageUploaded($event)"
2783
+ * (removed)="onImageRemoved()"
2784
+ * />
2785
+ * ```
2272
2786
  */
2273
- interface AgentDraggableItem<T = unknown> {
2274
- /** Stable id within its app. Used as a list key in the kbd menu. */
2275
- readonly id: string;
2276
- readonly labelKey: string;
2277
- readonly icon?: string;
2278
- /** Builds the payload the moment the user picks the item. */
2279
- build(): AgentDragPayload<T>;
2787
+ declare class FlyImageUploadComponent {
2788
+ private http;
2789
+ private injector;
2790
+ aspectRatio: _angular_core.InputSignal<number>;
2791
+ maxSizeBytes: _angular_core.InputSignal<number>;
2792
+ currentImageId: _angular_core.InputSignal<string | null>;
2793
+ sourceApp: _angular_core.InputSignal<string>;
2794
+ sourceEntityType: _angular_core.InputSignal<string | null>;
2795
+ sourceEntityId: _angular_core.InputSignal<string | null>;
2796
+ uploaded: _angular_core.OutputEmitterRef<FlyFileInfo>;
2797
+ removed: _angular_core.OutputEmitterRef<void>;
2798
+ uploading: _angular_core.WritableSignal<boolean>;
2799
+ error: _angular_core.WritableSignal<string | null>;
2800
+ showCropper: _angular_core.WritableSignal<boolean>;
2801
+ rawImageUrl: _angular_core.WritableSignal<string>;
2802
+ localBlob: _angular_core.WritableSignal<string | null>;
2803
+ fileInput: _angular_core.Signal<ElementRef<HTMLInputElement> | undefined>;
2804
+ cropImage: _angular_core.Signal<ElementRef<HTMLImageElement> | undefined>;
2805
+ private cropper;
2806
+ private selectedFile;
2807
+ /** Resolved preview URL — uses blob for local uploads, fetches authenticated for existing images */
2808
+ previewUrl: _angular_core.WritableSignal<string | null>;
2809
+ constructor();
2810
+ sizeHint: _angular_core.Signal<string>;
2811
+ triggerFileInput(): void;
2812
+ onDragOver(e: DragEvent): void;
2813
+ onDrop(e: DragEvent): void;
2814
+ onFileSelected(e: Event): void;
2815
+ removeImage(): void;
2816
+ cancelCrop(): void;
2817
+ applyCrop(): void;
2818
+ private processFile;
2819
+ private initCropper;
2820
+ private destroyCropper;
2821
+ private uploadFile;
2822
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<FlyImageUploadComponent, never>;
2823
+ 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>;
2280
2824
  }
2281
- /** Registry input shape for binding a chip-renderer component to a kind+appId pair. */
2282
- interface AgentDropRendererRegistration<T = unknown> {
2283
- readonly kind: string;
2284
- readonly appId: string;
2285
- readonly component: Type<AgentChipHostInputs<T>>;
2825
+
2826
+ interface UploadSlot {
2827
+ file: File;
2828
+ progress: number;
2829
+ status: 'uploading' | 'done' | 'error';
2830
+ info?: FlyFileInfo;
2831
+ error?: string;
2286
2832
  }
2287
2833
  /**
2288
- * Caps applied by {@link validateAgentPayload} / {@link trimAgentPayload}. The defaults
2289
- * trade off "fits comfortably in a single MQ frame" against "covers a richly-populated
2290
- * trend or note card". Hosts may pass a partial override.
2834
+ * Multi-file upload with drag-drop, progress, and validation.
2835
+ *
2836
+ * Usage:
2837
+ * ```html
2838
+ * <fly-file-upload
2839
+ * [maxFiles]="5"
2840
+ * [maxFileSizeBytes]="5242880"
2841
+ * accept=".pdf,.docx,.xlsx"
2842
+ * [(files)]="trend.attachments"
2843
+ * sourceApp="circles"
2844
+ * sourceEntityType="trend"
2845
+ * (filesChanged)="onAttachmentsChanged($event)"
2846
+ * />
2847
+ * ```
2291
2848
  */
2292
- interface AgentPayloadLimits {
2293
- /** Cap on the JSON.stringify(envelope) byte length. Default 32 KB. */
2294
- readonly maxJsonBytes: number;
2295
- /** Cap on the plainTextFallback byte length. Default 8 KB. */
2296
- readonly maxPlainTextFallbackBytes: number;
2297
- /** Cap on any single string field inside payload (recursive). Default 4 KB. */
2298
- readonly maxStringFieldBytes: number;
2299
- /** Cap on `userMessage` UTF-8 byte length. Default 280 chars (~1.1 KB). */
2300
- readonly maxUserMessageBytes: number;
2301
- /** Max entries in `systemContext`. Default 32. */
2302
- readonly maxSystemContextEntries: number;
2303
- /** Cap on any single systemContext value's UTF-8 byte length. Default 4 KB. */
2304
- readonly maxSystemContextValueBytes: number;
2305
- /** Cap on the full JSON.stringify(systemContext). Default 8 KB. */
2306
- readonly maxSystemContextJsonBytes: number;
2307
- /** Max attachments per envelope. Default 4. */
2308
- readonly maxAttachments: number;
2309
- /** Cap on a `json` attachment's serialized body. Default 16 KB. */
2310
- readonly maxAttachmentJsonBytes: number;
2311
- /** Cap on a `text` attachment's body bytes. Default 8 KB. */
2312
- readonly maxAttachmentTextBytes: number;
2313
- /** Cap on an `image` / `file` attachment's dataUrl bytes. Default 32 KB. */
2314
- readonly maxAttachmentDataUrlBytes: number;
2315
- /** Max prefixes in `mcpScope.apis`. Default 5. */
2316
- readonly maxMcpScopeApis: number;
2317
- /** Cap on any single mcpScope prefix string. Default 128 chars. */
2318
- readonly maxMcpScopeApiBytes: number;
2319
- /**
2320
- * Cap on `deepLinkRoute` UTF-8 byte length. Default 1024 bytes — matches
2321
- * the route limit on `DeepLinkService.isValidRoute` so this field can be
2322
- * handed straight to the shell launcher without a second resize.
2323
- */
2324
- readonly maxDeepLinkRouteBytes: number;
2849
+ declare class FlyFileUploadComponent {
2850
+ private http;
2851
+ maxFiles: _angular_core.InputSignal<number>;
2852
+ maxFileSizeBytes: _angular_core.InputSignal<number>;
2853
+ accept: _angular_core.InputSignal<string>;
2854
+ sourceApp: _angular_core.InputSignal<string>;
2855
+ sourceEntityType: _angular_core.InputSignal<string | null>;
2856
+ sourceEntityId: _angular_core.InputSignal<string | null>;
2857
+ /** Optional: provide file IDs to auto-fetch metadata for pre-existing files (edit mode). */
2858
+ existingFileIds: _angular_core.InputSignal<string[] | null>;
2859
+ /** Two-way model for completed file metadata. */
2860
+ files: _angular_core.ModelSignal<FlyFileInfo[]>;
2861
+ filesChanged: _angular_core.OutputEmitterRef<FlyFileInfo[]>;
2862
+ error: _angular_core.WritableSignal<string | null>;
2863
+ dragging: _angular_core.WritableSignal<boolean>;
2864
+ slots: _angular_core.WritableSignal<UploadSlot[]>;
2865
+ /** Pre-existing files loaded from the entity (before any new uploads this session). */
2866
+ existingFiles: _angular_core.WritableSignal<FlyFileInfo[]>;
2867
+ fileInput: _angular_core.Signal<ElementRef<HTMLInputElement> | undefined>;
2868
+ constructor();
2869
+ allSlots: _angular_core.Signal<UploadSlot[]>;
2870
+ canAddMore: _angular_core.Signal<boolean>;
2871
+ limitHint: _angular_core.Signal<string>;
2872
+ triggerFileInput(): void;
2873
+ onDragOver(e: DragEvent): void;
2874
+ onDragLeave(e: DragEvent): void;
2875
+ onDrop(e: DragEvent): void;
2876
+ onFilesSelected(e: Event): void;
2877
+ removeSlot(slot: UploadSlot): void;
2878
+ removeExisting(f: FlyFileInfo): void;
2879
+ iconFor(slot: UploadSlot): string;
2880
+ iconForInfo(f: FlyFileInfo): string;
2881
+ formatFileSize(bytes: number): string;
2882
+ private processFiles;
2883
+ private uploadFile;
2884
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<FlyFileUploadComponent, never>;
2885
+ 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>;
2325
2886
  }
2326
- declare const DEFAULT_AGENT_PAYLOAD_LIMITS: AgentPayloadLimits;
2327
- /**
2328
- * Stable failure reasons emitted by {@link validateAgentPayload}.
2329
- * - `invalid_version` — `version` !== {@link AGENT_PAYLOAD_VERSION}.
2330
- * - `invalid_kind` — `kind` is empty / not a string.
2331
- * - `field_too_large` — a string field inside `payload` exceeds `maxStringFieldBytes`.
2332
- * - `fallback_too_large` — `plainTextFallback` exceeds `maxPlainTextFallbackBytes`.
2333
- * - `json_too_large` — the full JSON.stringify(envelope) exceeds `maxJsonBytes`.
2334
- */
2335
- type AgentPayloadValidationResult = {
2336
- readonly ok: true;
2337
- } | {
2338
- readonly ok: false;
2339
- 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';
2340
- /** Dotted property-access path to the offending field, e.g. `payload.title` or `payload.tags[2]`. NOT RFC 6901 JSON Pointer. */
2341
- readonly fieldPath?: string;
2342
- readonly actualBytes?: number;
2343
- readonly limitBytes?: number;
2344
- };
2345
2887
 
2346
2888
  /**
2347
2889
  * Singleton registry of slash commands offered by the agent input palette.
@@ -2395,12 +2937,18 @@ declare class AgentCommandRegistry {
2395
2937
  /**
2396
2938
  * Singleton registry of entity lookups offered by the `/lookup` typeahead.
2397
2939
  *
2398
- * Mirrors {@link AgentCommandRegistry} exactly — same federation-singleton story
2399
- * (`sharedMappings: ['@mohamedatia/fly-design-system']`), same id-collision
2400
- * "latest wins" contract, same disposable-handle ergonomics. Federated remotes
2401
- * register their lookupable entities at boot (Circles: scenario / trend / signal)
2402
- * and dispose on window close, so the picker only ever offers entities whose app
2403
- * is currently live.
2940
+ * Mirrors {@link AgentCommandRegistry}'s federation-singleton story
2941
+ * (`sharedMappings: ['@mohamedatia/fly-design-system']`), id-collision
2942
+ * "latest wins" contract, and disposable-handle ergonomics. OS-core entities
2943
+ * (note / calendar event / file) register once at shell bootstrap via
2944
+ * `CORE_APP_LOOKUPS`; federated remotes (Circles: scenario / trend / signal)
2945
+ * register at remote-component boot and dispose on window close.
2946
+ *
2947
+ * **Scope semantics diverge from commands.** Commands HIDE when their `appId`
2948
+ * isn't in `liveAppIds`. Lookups DO NOT — they're always offered, and
2949
+ * `{appId}` is just a *priority hint* that bumps that lookup to the top of
2950
+ * the entity picker when the app is live. See {@link LookupRegistration.scope}
2951
+ * for the rationale.
2404
2952
  *
2405
2953
  * Storage is a signal store keyed on {@link LookupRegistration.entity}. Because
2406
2954
  * `entity` is the collision key, an app re-registering the same entity replaces
@@ -2411,10 +2959,18 @@ declare class AgentLookupRegistry {
2411
2959
  /** All currently-registered lookups, in insertion order. */
2412
2960
  readonly all: Signal<readonly LookupRegistration[]>;
2413
2961
  /**
2414
- * Lookups whose scope is `'global'` OR whose `scope.appId` is in the live app
2415
- * set. Recomputes when either the registry or `liveAppIds` changes — pass a
2962
+ * All registered lookups, sorted by affinity to `liveAppIds`:
2963
+ *
2964
+ * 1. Lookups whose `scope.appId` is in the live app set (in registration
2965
+ * order within that bucket).
2966
+ * 2. Then everything else — `'global'` lookups AND scoped lookups whose
2967
+ * app isn't currently live — in registration order.
2968
+ *
2969
+ * Recomputes when either the registry or `liveAppIds` changes. Pass a
2416
2970
  * `Signal<ReadonlySet<string>>` from the host's app-registry for reactive
2417
- * filtering, exactly like {@link AgentCommandRegistry.visible}.
2971
+ * re-sorting. **Always returns the full registry** — see the type doc on
2972
+ * {@link LookupRegistration.scope} for why this differs from
2973
+ * {@link AgentCommandRegistry.visible}.
2418
2974
  */
2419
2975
  visible(liveAppIds: ReadonlySet<string> | Signal<ReadonlySet<string>>): Signal<readonly LookupRegistration[]>;
2420
2976
  /**
@@ -2429,6 +2985,45 @@ declare class AgentLookupRegistry {
2429
2985
  * follow the standard "latest wins" rule and do NOT trigger rollback.
2430
2986
  */
2431
2987
  registerAll(lookups: readonly LookupRegistration[]): LookupHandle;
2988
+ /**
2989
+ * Resolve a deep-link anchor to a concrete launch target.
2990
+ *
2991
+ * `kind` is the dotted `<appId>.<entity>` token the agents backend emits
2992
+ * inside `flyos:<kind>/<id>` chat-answer anchors — the same entity-kind
2993
+ * vocabulary as drag-payload kinds and `ref` parts. Returns
2994
+ * `{ appId, route }` when a registered lookup for that `(appId, entity)`
2995
+ * pair carries a {@link LookupDescriptor.deepLinkRoute} template; `null`
2996
+ * otherwise (unknown entity, app mismatch, or no template — e.g. the
2997
+ * owning app isn't installed) so the caller renders plain text rather than
2998
+ * a dead link.
2999
+ *
3000
+ * `appId` and `entity` are both dot-free by their own grammars, so the
3001
+ * FIRST dot is the unambiguous split point; a dotless `kind` can't carry an
3002
+ * app and never resolves. The template's single `{id}` placeholder is
3003
+ * substituted URL-encoded.
3004
+ */
3005
+ resolveDeepLink(kind: string, id: string): {
3006
+ readonly appId: string;
3007
+ readonly route: string;
3008
+ } | null;
3009
+ /**
3010
+ * Resolve a deep-link target from a bare `(entity, id)` pair — the shape a
3011
+ * `/lookup` ref carries (it has no `<appId>.<entity>` kind token; the owning
3012
+ * app is implicit in the registered descriptor). `entity` is the registry's
3013
+ * unique storage key, so it identifies the descriptor unambiguously without
3014
+ * an app prefix.
3015
+ *
3016
+ * Returns `{ appId, route }` (the descriptor's {@link LookupDescriptor.appId}
3017
+ * / affinity `scope.appId` as the owner, `{id}` substituted URL-encoded) when
3018
+ * a matching descriptor carries a {@link LookupDescriptor.deepLinkRoute};
3019
+ * `null` otherwise (unknown entity, no template, or the owning app has since
3020
+ * unregistered) so callers render plain text rather than a dead link — the
3021
+ * same graceful-degrade contract as {@link resolveDeepLink}.
3022
+ */
3023
+ resolveDeepLinkForEntity(entity: string, id: string): {
3024
+ readonly appId: string;
3025
+ readonly route: string;
3026
+ } | null;
2432
3027
  /** Tear down by entity. Idempotent. */
2433
3028
  unregister(entity: string): void;
2434
3029
  /** Monotonic counter; identifies which registration call currently owns each entity. */
@@ -2975,6 +3570,6 @@ declare const AUDIENCE_ERROR_CODES: {
2975
3570
  };
2976
3571
  type AudienceErrorCode = (typeof AUDIENCE_ERROR_CODES)[keyof typeof AUDIENCE_ERROR_CODES];
2977
3572
 
2978
- 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_ROUTES, FLY_THEME_MODE_IDS, FLY_WINDOW_HELP_HINT_EVENT, FlyAgentDraggableDirective, FlyBlockUiComponent, FlyFileUploadComponent, FlyImageUploadComponent, 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 };
2979
- export type { AgentAction, AgentActionDispatch, AgentActionVerb, AgentChipHostInputs, AgentCommand, AgentCommandHandle, AgentCommandRegistration, AgentCommandScope, 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, 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 };
3573
+ 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, 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, 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 };
3574
+ 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, 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 };
2980
3575
  //# sourceMappingURL=mohamedatia-fly-design-system.d.ts.map